Reputation: 1687
I'm trying to pass extra props to this.props.children, I saw this answer how to pass props to children with React.cloneElement?
and from some reason although I'm not getting any error I can't see the prop
So I have this state
this.state = {
open: true
}
and I want to pass it down to this.props.children, and this is what I've done so far:
{
React.Children.map(this.props.children, child =>
React.cloneElement(child, {sidebarState: this.state.open}))
}
and when I'm console.logging this.props on the children I can't see my new props.
--- EDIT --- In the children it looks like this:
render() {
console.log(this.props)
// other code
}
BTW I'm using react 16.0
Upvotes: 5
Views: 12964
Reputation: 17999
Here is an example.
Before (without passing props down to the children
):
<div className="layout">
{children}
</div>
After (passing extra props1
and props2
props to every child):
<div className="layout">
{
React.Children.map(children, (child) => {
return React.cloneElement(child, {
props1: 1,
props2: 2,
});
})
}
</div>
props1
andprops2
get merged with the existing props for every child.
Regarding TypeScript types, you have to use React.ReactElement
instead of React.ReactNode
or the TS compiler will complain at React.Children.map
(or ts-ignore it):
type Props = {
children: React.ReactElement;
};
See https://medium.com/better-programming/passing-data-to-props-children-in-react-5399baea0356 for more explanation, that helped me a lot to understand how to do it! (#mediumPaywall)
Upvotes: 7
Reputation: 191936
There are two ways to pass props to children:
Children as function
Instead of being a React element, children can be a function.
Call the children function:
const List = ({ children, sidebarState }) => (
<ul>
{
children(sidebarState)
}
</ul>
);
Passing the children a function:
<List sidebarState={sidebarState}>
{
(sidebarState) => (
<Item sidebarState={sidebarState} />
)
}
</List>
Working example:
const { Component } = React;
const Item = ({ sidebarState }) => (
<li>{sidebarState ? 'open' : 'close'}</li>
);
const List = ({ children, sidebarState }) => (
<ul>
{
children(sidebarState)
}
</ul>
);
class App extends Component {
constructor(props) {
super(props);
this.state = {
sidebarState: true
}
}
toggleOpen = () => this.setState((prevState) => ({
sidebarState: !prevState.sidebarState
}));
render() {
const { sidebarState } = this.state;
return (
<div>
<button onClick={this.toggleOpen}>Toggle</button>
<List sidebarState={sidebarState}>
{
(sidebarState) => (
<Item sidebarState={sidebarState} />
)
}
</List>
</div>
);
}
}
ReactDOM.render(
<App />,
demo
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="demo"></div>
React.cloneElement
Working example:
const { Component } = React;
const Item1 = ({ sidebarState }) => (
<li>{sidebarState ? 'open' : 'close'}</li>
);
const Item2 = ({ sidebarState }) => (
<li>{sidebarState ? 'open' : 'close'}</li>
);
const List = ({ children, sidebarState }) => (
<ul>
{
React.Children.map(children, (child) => React.cloneElement(child, { sidebarState }))
}
</ul>
);
class App extends Component {
constructor(props) {
super(props);
this.state = {
sidebarState: true
}
}
toggleOpen = () => this.setState((prevState) => ({
sidebarState: !prevState.sidebarState
}));
render() {
const { sidebarState } = this.state;
return (
<div>
<button onClick={this.toggleOpen}>Toggle</button>
<List sidebarState={sidebarState}>
<Item1 />
<Item2 />
</List>
</div>
);
}
}
ReactDOM.render(
<App />,
demo
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="demo"></div>
Upvotes: 3