简体   繁体   English

ReactJS从大子级控制父级中的状态

[英]Reactjs controlling state in parent from grand child

I have at my top level: 我在最高层:

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>
        );
    }
}

Modal is: 模态为:

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;

But I want to open and close it (as well as send data to it later) from within a deeper component: 但是我想从一个更深的组件中打开和关闭它(以及以后发送数据):

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>
        )
    }
};

Obviously this doesn't work because toggleModal is all the way up in JobScreen. 显然,这是行不通的,因为toggleModal在JobScreen中一直处于上升状态。 How can I execute the function in the grandparent from this depth? 如何从这个深度在祖父母中执行功能?

If your JobScreen , JobList , Job and Modal components are designed to be tightly coupled, ie not meant to be separated from each other in future, you could use the JobScreen as a High Order Component to store the state of your modal and passing down the tree as prop a callback function to update this state (I simplified a bit and made some assumptions on missing components) : 如果将JobScreenJobListJobModal组件设计为紧密耦合,即将来不打算彼此分离,则可以将JobScreen用作高阶组件来存储模态的状态并向下传递树作为支持回调函数来更新此状态的支柱(我简化了一点,并对缺少的组件进行了一些假设):

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>
    );

}

I deliberately not mentions how to modify the modal children this way cause it's an absolute anti-pattern. 我故意不提及如何以这种方式修改模式子对象,因为这是绝对的反模式。 So, you should definitively look at something like Redux which provides a way to manage the state of your application and dispatch action from wherever you want to update in a 'one way data binding' way. 因此,您应该明确地看一下Redux之类的东西,它提供了一种管理应用程序状态并从任何要以“单向数据绑定”方式进行更新的地方分派操作的方法。 I've the impression you're trying to bypass the React internal mechanisms by using context as an action dispatcher. 我给你的印象是您试图通过使用context作为动作分派器来绕过React内部机制。 So, Redux (or another Flux library) will be your best bet here. 因此,Redux(或其他Flux库)将是您最好的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM