8

Say I have

<component1>
     <component2>
           <component3>
                 <component4>

(where component1 has a child component2, component2 has a child component3, component3 has a child component4 )

and say I want to pass something from component1 into component4 . Do I need to pass props down the chain? so component1 -> component2 -> component3 -> component4

?

Please note: these components are not in the same file. so in component1.js I refer to <component2> and in component2.js I refer to <component3> etc.

Shai UI
  • 50,568
  • 73
  • 204
  • 309

3 Answers3

9

You have 2 main options here:

  1. Pass down the props.
  2. Use the context API

With props you also got 2 main options:

  1. You can pass the props implicit

    <Parent>
      <ChildOne {...props}>
        <ChildTwo {...props}>
        </ChildTwo>
      </ChildOne>
    </Parent>
    

    Running snippet for implicit props:

    const ChildTwo = props => (
      <div>{`Child two says: ${props.myProp}`}</div>
    );
    
    const ChildOne = props => (
      <div>
        <ChildTwo {...props} />
      </div>
    );
    
    const Parent = props => (
          <div>
            <ChildOne  {...props} />
          </div>
        );
    
    ReactDOM.render(<Parent myProp="hi there" />, document.getElementById('root'));
    <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="root"></div>
  2. Or do it explicit

    <Parent>
      <ChildOne propOne={propOne}>
        <ChildTwo propOne={propOne}>
        </ChildTwo>
      </ChildOne>
    </Parent>
    

    Running snippet for explicit props:

const ChildTwo = (props) => (
  <div>{`Child two says: ${props.myProp}`}</div>
);

const ChildOne = props => (
  <div>
    <ChildTwo myProp={props.myProp} />
  </div>
);

const Parent = props => (
      <div>
        <ChildOne  myProp={props.myProp} />
      </div>
    );

ReactDOM.render(<Parent myProp="hi there" />, document.getElementById('root'));
<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="root"></div>

As for the context API, you can skip levels and "grab" props from grandparents.
This is what react-redux does behind the scenes.

Running example of the context API:

const ChildTwo = (props, context) => (
  <div>{`Child two says: ${context.myProp}`}</div>
);

ChildTwo.contextTypes = { myProp: React.PropTypes.string }

const ChildOne = props => (
  <div>
    <ChildTwo />
  </div>
);

class Parent extends React.Component {

  getChildContext() {
    const { myProp } = this.props;
    return { myProp };
  }

  render() {
    return (
      <div>
        <ChildOne />
      </div>
    );
  }
}

Parent.childContextTypes = {
  myProp: React.PropTypes.string
};

ReactDOM.render(<Parent myProp="hi there" />, document.getElementById('root'));
<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="root"></div>

Note that this example is using react v15, which the syntax for React.PropTypes is changed, Since react v16 PropTypes is no longer part of the react library and it was extracted to another library prop-types.

Also Note, that the docs advise against the usage of the context API:

If you aren’t an experienced React developer, don’t use context. There is usually a better way to implement functionality just using props and state.

Sagiv b.g
  • 30,379
  • 9
  • 68
  • 99
2

You can use React's inbuilt Context API, although I wouldn't suggest you rely too much on this because this either could get deprecated or be made into a full stable feature. As of now Facebook warns users with some points in their docs WARNING. Without that hiccup, the API is just wonderful and helps maintain neat code without having to send props all the way to the intended descendant.

CONTEXT API

COMPONENT 1

class Component1 extends React.Component {
  getChildContext() {
    return {
      yourProp: "someValue" // you can also add a function like yourProp: someFunc
    };
  }

  render() {
    <Component2 />
  }
}

Component1.childContextTypes = {
  yourProp: PropTypes.string
};

COMPONENT 2

class Component2 extends React.Component {
  render() {
    return (
      <Component3 />
    );
  }
}

COMPONENT 3

class Component3 extends React.Component {
  render() {
    return (
      <Component4 />
    );
  }
}

COMPONENT4

class Component4 extends React.Component {
  render() {
    return (
      <div>
        {this.context.yourProp}      
      </div>
    );
  }
}

Component4.contextTypes = {
  yourProp: PropTypes.string
};

There are quite many strategies if you don't choose to use this.

  • REDUX
  • EVENT EMITTER
  • PASSING PROPS ALL THE WAY TO THE DESCENDANT
Nandu Kalidindi
  • 6,075
  • 1
  • 23
  • 36
0

Yes with using just React you would need to pass down props through each component, even if the component doesn't use that prop. So in your example control2 & control3 don't care about the prop but need to pass it down. Below is what you would need to do.

<Control1 test={this.state.test}>
  <Control2 test={this.props.test}>
    <Control3 test={this.props.test}>
      <Control4 test={this.props.test} />
    </Control3>
  </Control2>
</Control1>

This can get cumbersome so this is a case where redux can help.

BPedersen
  • 34
  • 1
  • 2
  • these components are not in the same file. so in component1.js I refer to ... and in component2.js I refer to etc. – Shai UI Jan 08 '18 at 20:14