【问题标题】:Reactjs controlling state in parent from grand childReactjs从孙子控制父母的状态
【发布时间】:2016-04-26 06:41:22
【问题描述】:

我的最高级别是:

import React from 'react';
import JobList from './JobList';
import RightPanel from './RightPanel';

import JobStore from '../../stores/JobStore';
import LoadJobsScreen from '../../actions/jobs-screen/LoadJobsScreen';
import Modal from '../global/Modal';

export default class JobScreen extends React.Component {

    static contextTypes = {
        executeAction: React.PropTypes.func.isRequired
    };

    componentWillMount() {
        this.toggleModal = this.toggleModal.bind(this);
        this.state = {open: false}
        this.context.executeAction(LoadJobsScreen, this);
    }

    toggleModal() {
        this.setState({
            open: !this.state.open
        });
        console.log(this.state.open);
    }

    render() {
        return (
            <div className="jobs-screen">
                <div className="col-xs-12 col-sm-10 job-list"><JobList /></div>
                <div className="col-xs-12 col-sm-2 panel-container">
                    <div className="right-panel pull-right"><RightPanel /></div>
                </div>
                <Modal open={this.state.open} toggleModal={this.toggleModal} />
            </div>
        );
    }
}

模态是:

import React from 'react';

class Modal extends React.Component {
    constructor() {
        super();
    }

    render() {
        let open = this.props.open;
        return (
            <div className={'modal fade'+(open ? '' : ' hide')} tabindex="-1" role="dialog">
                <div className="modal-dialog">
                    <div className="modal-content">
                        <div className="modal-header">
                            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                            <h4 className="modal-title">{this.props.title}</h4>
                        </div>
                        <div className="modal-body">
                            {this.props.children}
                        </div>
                        <div className="modal-footer">
                            <button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
                            <button type="button" className="btn btn-primary">Save changes</button>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

export default Modal;

但我想从更深的组件中打开和关闭它(以及稍后向它发送数据):

import React from 'react';
import UrgencyToggle from './UrgencyToggle';
import ApproveButton from './ApproveButton';
import ShippingTable from './ShippingTable';
import DropdownButtonList from '../global/DropdownButtonList';

export default class Job extends React.Component {
    constructor(props) {
        super(props);

    }

    setUrgency(urgency) {
        actionContext.dispatch('SET_JOB_URGENCY', {
            data: urgency
        })
    };

    render() {
        return ( <
            span className = "name" > < img src = "/images/system-icons/pencil.png"
            onClick = {
                this.toggleModal
            }
            width = "13" / > < /span>
        )
    }
};

显然这不起作用,因为 toggleModal 一直在 JobScreen 中。如何从这个深度执行祖父母中的功能?

【问题讨论】:

  • 为什么不直接通过子组件上的 props 传递 toggleModal 回调?
  • 喜欢这个?:
  • 您必须将顶级组件的toggleModal 回调传递给您的子组件,但在您的示例中,您根本不使用您的Job 组件,这里有一个问题。
  • 或者你的 Job 组件被用作 JobList 组件的子组件,在这种情况下,你必须将 toggleModal 向下传递,即来自 JobScreen 组件到JobList 通过JobList 道具和从JobList 组件到Job 组件通过Job 道具。在您的问题中添加您的JobList 组件的代码,我将发布带有详细代码的答案:)
  • 我想知道,但这不是有点笨拙吗?肯定有更好的方法吗?

标签: javascript reactjs ecmascript-6


【解决方案1】:

如果您的 JobScreenJobListJobModal 组件设计为紧密耦合,即将来不会相互分离,您可以使用 JobScreen 作为 @ 987654321@ 存储模态的状态并将树作为道具传递一个回调函数来更新此状态(我简化了一点并对缺少的组件做了一些假设):

export default class JobScreen extends React.Component {

    constructor(props) {
        super(props);
        this.displayName = 'JobScreen'
        this.state = {
            modalOpened: false,
            modalTitle: "",
        }
    }
    componentWillMount() {
        this.context.executeAction(LoadJobsScreen, this);
    }

    toggleModal() {
        this.setState({
            modalOpened: !this.state.modalOpened
        });
    }

    editModalTitle(title) {
        this.setState({
            modalTitle: title
        })
    }

    render() {
        return (
            <div className="jobs-screen">
                <div className="col-xs-12 col-sm-10 job-list">
                    <JobList
                        toggleModal={() => this.toggleModal() /* auto binding with arrow func */}
                        editModalTitle={(title) => this.editModalTitle(title)} />
                </div>
                <Modal
                    open={this.state.modalOpened}
                    title={this.state.modalTitle}/>
            </div>
        );
    }
}

const JobList = (props) => {

    const jobs = [1,2,3]

    return (
        <ul>
            {jobs.map(key => (
                <li key={key}>
                    <Job
                        toggleModal={props.toggleModal}
                        editModalTitle={props.editModalTitle}/>
                </li>
            ))}
        </ul>
    );

}

const Job = (props) => {

    return (
        <span className="name">
            <img
                src="/images/system-icons/pencil.png"
                width="13"
                onClick={(e) => {
                    props.toggleModal(e)
                    props.editModalTitle("new title") //not very efficient here cause we're updating state twice instead of once, but it's just for the sake of the example
                }}/>
        </span>
    );

}

我故意没有提到如何以这种方式修改模态子项,因为它是绝对反模式。因此,您应该明确地查看Redux 之类的东西,它提供了一种管理应用程序状态的方法,并从您想要以“单向数据绑定”方式更新的任何地方分派操作。我的印象是您试图通过使用 context 作为动作调度程序来绕过 React 内部机制。因此,Redux(或其他 Flux 库)将是您最好的选择。

【讨论】:

    猜你喜欢
    • 2015-06-14
    • 2018-01-13
    • 1970-01-01
    • 1970-01-01
    • 2020-03-07
    • 1970-01-01
    • 2021-09-19
    • 2018-09-04
    • 1970-01-01
    相关资源
    最近更新 更多