简体   繁体   中英

What's the proper way to pass dependencies between components in React?

Imagine that Component A creates a list of items that Component B needs to display. What's the proper way to pass data from Component A to Component B from their parent?

For example, let's say that Component A's constructor creates a list of items and has a function _getListItems() that returns that list. I'm hoping the parent can then pass that list on to other components via props.

My naive (non-working) implementation has their parent attempting to render the components like this:

render () {
    return (
      <div>
        <h1>Data Test</h1>        
        <ComponentA ref='compa'/>
        <ComponentB items={this.refs.compa._getListItems()}/>
      </div>
    );
}

....although the code above doesn't work, I hope it illustrates what I'm trying to do.

ps. nOOb to react and javascript, so forgive me if the answer to my question's obvious...

Divide your components into two separate categories.

  • Presentational Component that has responsibility to display a thing. This component should not have state (except for UI state).
  • Container Component that knows the data.

https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.skmxo7vt4

So, in your case the data should created by parent of ComponentA and ComponentB and pass the data to both ComponentA and ComponentB via props.

Example:

render(){
    let items = this._getListItems();
    return (
        <div>
            <ComponentA items={items} />
            <ComponentB items={items} />
        </div>
    );
}

Edit

Rewrite OP's approach in the comment:

class MyContainer extends React.Component { 
    constructor(props) { 
        super(props);
        this.state = { stuff: [1,2,3] }; 
    } 

    render() { 
        return ( 
            <div>
                <ComponentA items={this.state.stuff} /> 
                <ComponentB items={this.state.stuff} /> 
            </div> 
        ); 
    } 
}

Following the accepted answer above, I've just had a (related) EUREKA moment, so I'm going to expand on the answer; when the parent uses its own state to pass props to its children, whenever the parent's state changes, its render() function is called, thus updating the children with the updated state. So you can do stuff like this:

class MyContainer extends React.Component { 
    constructor(props) { 
        super(props);

        let sltd = this.props.selected
        this.state = { 
          stuff: [1,2,3], 
          selected: sltd
        }; 
    } 

    _handleAStuff(value) {
        this.setState(selected: value)
        //do other stuff with selected...
    }

    _handleBStuff(value) {
        this.setState(selected: value)
        //do other stuff with selected...
    }

    render() { 
        return ( 
            <div>
                <ComponentA items={this.state.stuff} selected={this.state.selected} parentFunc={this._handleAStuff.bind(this)} /> 
                <ComponentB items={this.state.stuff} selected={this.state.selected} parentFunc={this._handleBStuff.bind(this)} /> 
            </div> 
        ); 
    } 
}

MyContainer.defaultProps = {
  selected: 0
}

class ComponentA extends React.Component {

  constructor(props) {
    super(props)
  }

  _handleSelect(value) {
    this.props.parentFunc(value.label)
  }

render() {

    const itm = this.props.items.map(function(values) {
      return { value: values, label: values}
    })

    return (
      <div>
        <Select
          options={itm}
          value={this.props.selected}
          onChange={this._handleSelect.bind(this)}
        />
      </div>
    );
  }
}

// ComponentB...

The callback pattern above means that ComponentA and ComponentB do not need to maintain state, they simply 'render stuff', which is also pretty cool. I'm beginning to see the power of REACT...

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