Reputation: 166
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.
Upvotes: 4
Views: 1917
Reputation: 24181
Update: Ther HOC, I've used inthe example is not what React call a HOC, not sure of the proper name for this sort of code,. Scoped Component maybe. On a side note, the reasons given for HOC's in the doc's, eg. (code reuse). Can be done much nicer now with Hooks.
To expand on the HOC (Higher Order Component) idea,.
Here is a simple example.
Notice how Comp4 didn't have to have props passed down from Comp2 & Comp3, this is because we have made Comp1 into a HOC. So although you could use Context's, the ideal would be to use HOC's were possible,. This is because each Component can always be treated in isolation, that makes debugging an re-usability so much better.
function Comp2(props) {
return <div>Comp2: <br/>{props.children}</div>
}
function Comp3(props) {
return <div>Comp3: <br/>{props.children}</div>
}
function Comp4(props) {
return <div>Comp4: {props.value}<br/>{props.children}</div>
}
function Comp1(props) {
return <div>
Comp1: {props.value}
<Comp2>
<Comp3>
<Comp4 value={props.value}/>
</Comp3>
</Comp2>
</div>
}
ReactDOM.render(
<Comp1 value={"This get passed to everything using a HOC"}/>,
document.querySelector("#mount")
);
div {
margin-left: 1em;
}
<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="mount"/>
Upvotes: 0
Reputation: 31024
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"/>
Upvotes: 4
Reputation: 195982
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
Upvotes: 3