Javascript 从grand child返回父级中的控制状态

Javascript 从grand child返回父级中的控制状态,javascript,reactjs,ecmascript-6,Javascript,Reactjs,Ecmascript 6,我的最高级别: 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 '../glo

我的最高级别:

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>
        );
    }
}
从“React”导入React;
从“./作业列表”导入作业列表;
从“/RightPanel”导入RightPanel;
从“../../stores/JobStore”导入JobStore;
从“../../actions/jobs screen/LoadJobsScreen”导入LoadJobsScreen;
从“../global/Modal”导入模态;
导出默认类JobScreen扩展React.Component{
静态上下文类型={
执行操作:需要React.PropTypes.func.isRequired
};
组件willmount(){
this.toggleModal=this.toggleModal.bind(this);
this.state={open:false}
this.context.executeAction(LoadJobsScreen,this);
}
toggleModal(){
这是我的国家({
打开:!this.state.open
});
console.log(this.state.open);
}
render(){
返回(
);
}
}
模式是:

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;
从“React”导入React;
类Modal扩展了React.Component{
构造函数(){
超级();
}
render(){
让打开=this.props.open;
返回(
&时代;
{this.props.title}
{this.props.children}
接近
保存更改
)
}
}
导出默认模式;
但我想从更深层次的组件中打开和关闭它(以及稍后向它发送数据):

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>
        )
    }
};
从“React”导入React;
从“/UrgencyToggle”导入UrgencyToggle;
从“/ApproveButton”导入ApproveButton;
从“/ShippingTable”导入ShippingTable;
从“../global/DropdownButtonList”导入DropdownButtonList;
导出默认类作业扩展React.Component{
建造师(道具){
超级(道具);
}
紧急(紧急){
actionContext.dispatch('SET\u JOB\u emergency'{
数据:紧迫性
})
};
render(){
报税表(<
span className=“name”>
)
}
};

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

如果您的
作业屏幕
作业列表
作业
模态
组件设计为紧密耦合,即未来不会彼此分离,您可以使用
JobScreen
作为存储模态状态的工具,并将树作为回调函数向下传递以更新此状态(我简化了一点,并对缺少的组件做了一些假设):

导出默认类JobScreen扩展React.Component{
建造师(道具){
超级(道具);
this.displayName='JobScreen'
此.state={
莫达洛佩内德:错,
模态:“,
}
}
组件willmount(){
this.context.executeAction(LoadJobsScreen,this);
}
toggleModal(){
这是我的国家({
modalOpened:!this.state.modalOpened
});
}
编辑模式(标题){
这是我的国家({
模式:标题
})
}
render(){
返回(
this.toggleModal()/*与arrow func*/}
editModalTitle={(标题)=>this.editModalTitle(标题)}/>
);
}
}
常量作业列表=(道具)=>{
常量作业=[1,2,3]
返回(
    {jobs.map(键=>(
  • ))}
); } 常量作业=(道具)=>{ 返回( { 道具。切换模式(e) editModalTitle(“新标题”)//这里不是很有效,因为我们更新状态两次而不是一次,但这只是为了示例 }}/> ); }

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

为什么不通过子组件上的道具传递
toggleModal
回调?就像这样?:您必须将
toggleModal
回调从顶级组件传递到子组件,但是在您的示例中,您根本没有使用
作业
组件,这里有一个问题。或者您的
作业
组件被用作
作业列表
组件的子组件,在这种情况下,您必须将
切换模式
传递到树下,即通过
作业列表
道具从
作业屏幕
组件到
作业列表
,通过
作业
道具从
作业列表
组件到
作业
组件。在你的问题中添加你的
工作列表
组件的代码,我将发布一个带有详细代码的答案:)我想知道,但这不是有点笨拙吗?肯定有更好的办法吗?
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>
    );

}