2016-04-26 108 views
2

我在我的顶层控制父状态:Reactjs从盛大孩子

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中的所有方式。我如何从这个深度执行祖父母的功能?

+0

为什么不通过你的子组件上的道具来传递'toggleModal'回调? – Pcriulan

+0

像这样?:

imperium2335

+0

您必须将顶级组件的'toggleModal'回调传递给您的子组件,但在您的示例中根本不使用“Job”组件,这里存在问题。 – Pcriulan

回答

0

如果您JobScreenJobListJobModal部件被设计为紧耦合,即不意味着要在未来的相互分离,您可以使用JobScreen作为High Order Component来存储你的模式和传球的状态树倒为支撑的回调函数来更新这个状态(我简化了一下,并就缺少的组件一些假设):

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库)将成为您最好的选择。