Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing props to Children of Children (nested component tree)

I am not sure if this could be possible but here is the thing that I want to achieve in Reactjs:

<Comp1>
  <Comp2 />
  <Comp3>
    <Comp4 />
  </Comp3>
</Comp1>

So what I want to do is, I want to inject a prop from Comp1 component down to Comp4 component using React.cloneElement API. In that way, if I want to propagate a prop or set of props to may be a child at Level 6 down in hierarchy, I should be able to do that.

But what I managed to achieve uptil now is, the props are injected to the immediate Children but not the children of children.

Here is my effort to do it: https://codesandbox.io/s/x2q06l5z64

I guess I've made the problem clear, if there is a confusion, you can ask it away.

like image 371
Bilal Shafi Avatar asked Mar 04 '23 21:03

Bilal Shafi


2 Answers

This is a classic use case for react's context API.

const MyContext = React.createContext('');

class Parent extends React.Component {
  render() {
    const { message } = this.props;
    return (
      <MyContext.Provider value={message}>
        {this.props.children}
      </MyContext.Provider>
    )
  }
}

class Child extends React.Component {
  render() {
    return (
      <MyContext.Consumer>
        {(message) => (
          <div style={{ border: '1px solid #ccc' }}>
            <h3>Child</h3>
            {message}
          </div>
        )}
      </MyContext.Consumer>
    )
  }
}

class App extends React.Component {
  state = { message: 'default message' }
  handleChange = ({ target }) => this.setState({ message: target.value })
  render() {
    const { message } = this.state;
    return (
      <div className="App">
        <input value={message} onChange={this.handleChange} />
        <Parent message={message}>
          <div className="some-child">
            <div className="some-child">
              <div className="some-child">
                <div className="some-child">
                  <Child />
                </div>
              </div>
            </div>
          </div>
        </Parent>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
like image 155
Sagiv b.g Avatar answered Mar 18 '23 00:03

Sagiv b.g


You have your ternary logic reversed.

You original code was

return childzFurtherChildren
      ? React.cloneElement(child, { ...newProps, hello: true })
      : React.cloneElement(child, { ...newProps, hello: true }, childzFurtherChildren);

but it needs to be

return childzFurtherChildren
      ? React.cloneElement(child, { ...newProps, hello: true }, childzFurtherChildren)
      : React.cloneElement(child, { ...newProps, hello: true });

Because when you have further children (that have been processed) you then need to add them to the cloned element.

Updated demo at https://codesandbox.io/s/8n26lq6mj9

like image 33
Gabriele Petrioli Avatar answered Mar 17 '23 23:03

Gabriele Petrioli