简体   繁体   中英

Communication through 3 level components on ReactJS

I'm new developing for React and clearly I'm struggling in how to pass data through components. I have created an example on CodePen to try to understand the flow. The example is just an example of a return a value from a modal to the main level.

I have these levels of hierarchy:

  • Main
    • InsideComponent
      • Form
        • Input Field

Inside my main component I have a span that I would like to update when the text inside the input field is typed.

I'm using props to pass callbacks and return the value that I need. So, Is there a better way to pass those changes to my Main level?

PS: I saw a lot of examples here on StackOverflow, but I couldn't see this example without Redux or Flux.

My code:

 class Main extends React.Component { constructor(props) { super(props); this.state = { text: '' } this.onUpdateLabel = this.onUpdateLabel.bind(this); } onUpdateLabel(value) { this.setState({ text: value }); } render() { let value = this.state.text != '' ? this.state.text : 'Waiting...'; return ( <div> <h1>Main</h1> <span class='label'>{value}</span> <hr /> <Modal onUpdateLabel={this.onUpdateLabel} /> </div> ); } } class Modal extends React.Component { constructor(props) { super(props); } render() { this.props.text = 'Inside Component'; return ( <div> <h2>Modal</h2> <Form onUpdateLabel={this.props.onUpdateLabel} /> </div> ) } } class Form extends React.Component { constructor(props) { super(props); this.state = { text: '' } this.onClickButton = this.onClickButton.bind(this); this.onUpdateText = this.onUpdateText.bind(this); } onUpdateText(e) { this.setState({ text: e.target.value }); } onClickButton() { this.props.onUpdateLabel(this.state.text); } render() { return ( <div> <h3>Form</h3> <input type='text' placeholder='Type something' onChange={this.onUpdateText} /> <button onClick={this.onClickButton}>Click</button> </div> ); } } ReactDOM.render( <Main />, document.getElementById('app') ); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="app"></div> 

You could use the Context but as it is stated in the doc:

It is an experimental API and it is likely to break in future releases of React.

If you decide to still use it, you would write something like that:

class Main extends React.Component {
  static childContextTypes = { // Define the child context
      onUpdateLabel: PropTypes.func,
  }

  constructor(props) {
    super(props);
    this.state = {
      text: ''
    }
    this.onUpdateLabel = this.onUpdateLabel.bind(this);
  }

  onUpdateLabel(e) {
    this.setState({ text: e.target.value });
  }

  getChildContext(){ // Return the wanted context
      return {
          onUpdateLabel: this.onUpdateLabel,
      }
  }

  render() {...}
}

and in your Form

class Form extends React.Component {

  static contextTypes = { // Define the available context
      onUpdateLabel: PropTypes.func,
  }

  constructor(props) {
    super(props);
    this.state = {
      text: ''
    }
    this.onClickButton = this.onClickButton.bind(this);
    this.onUpdateText = this.onUpdateText.bind(this);
  }

  onUpdateText(e) {
    this.setState({ text: e.target.value });
  }

  onClickButton() { // Retrieve it from context instead of props
    this.context.onUpdateLabel(this.state.text);
  }

  render(){...}
}

You define the context in the main element, and use it in one of the children.

Your method is alright you were calling

e.target.value

where it's not present

onUpdateLabel(text) {
   this.setState({ text: text });
}

 class Main extends React.Component { constructor(props) { super(props); this.state = { text: '' } this.onUpdateLabel = this.onUpdateLabel.bind(this); } onUpdateLabel(text) { this.setState({ text: text }); } render() { let value = this.state.text != '' ? this.state.text : 'Waiting...'; return ( <div> <h1>Main</h1> <span class='label'>{value}</span> <hr /> <Modal onUpdateLabel={this.onUpdateLabel} /> </div> ); } } class Modal extends React.Component { constructor(props) { super(props); } render() { this.props.text = 'Inside Component'; return ( <div> <h2>Modal</h2> <Form onUpdateLabel={this.props.onUpdateLabel} /> </div> ) } } class Form extends React.Component { constructor(props) { super(props); this.state = { text: '' } this.onClickButton = this.onClickButton.bind(this); this.onUpdateText = this.onUpdateText.bind(this); } onUpdateText(e) { this.setState({ text: e.target.value }); } onClickButton() { this.props.onUpdateLabel(this.state.text); } render() { return ( <div> <h3>Form</h3> <input type='text' placeholder='Type something' onChange={this.onUpdateText} /> <button onClick={this.onClickButton}>Click</button> </div> ); } } ReactDOM.render(<Main />, document.getElementById('app')); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="app"></div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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