Reputation: 3561
I have a React component that clones its children with additional props. I'm using the standard childrenWithProps method that works great if your child is another react component but no clear way of doing this without a direct react component as the child.
<DataCmp>
<Fragment>
<h1>Example Code</h1>
<div>{isLoggedIn}</div>
</Fragment>
</DataCmp>
In this example, I have adding the prop myData
to the props of its children. However, this doesn't work. The child doesn't see the value. It will say myData is not set when it's passed in by props.
So I attempted this:
<DataCmp>
<Fragment>
<h1>Example Code</h1>
<div>{this.props.isLoggedIn}</div>
</Fragment>
</DataCmp>
This brings up errors as it has no idea what this.props.myData
is.
My next attempt was to wrap the child in an inline function and get the prop from that.
<DataCmp>
{({ isLoggedIn}) => (
<Fragment>
<h1>Example Code</h1>
<div>{isLoggedIn}</div>
</Fragment>
)}
</DataCmp>
While this doesn't bring up any errors; The child component is never rendered.
I'm working on updating and modernizing someone else old Github project. here is the link to my project and the wrapping component is Wallet.jsx the location that it's being used is index.jsx
The children are rendered as such:
renderChildren = () => {
const { children } = this.props;
const { accounts } = this.state;
const handleLogin = () => this.login();
const childrenWithProps = React.Children.map(children, (child, index) => {
if(typeof child == 'object') {
return React.cloneElement(child, {
key: index,
loginFn: () => handleLogin(),
isLoggedIn: accounts[0] !== '0x0',
accounts,
});
} else {
return child;
}
});
return childrenWithProps;
}
Upvotes: 1
Views: 212
Reputation: 2473
React.Children.map(children, fn)
only iterates over valid react elementsThis excludes, for example, functions passed as child. Passing a function-to-be-rendered as prop to a component is known as Render Props pattern. React.Children.map will not iterate over this, hence, your third option returned null
.
Fix it by checking whether children
is a valid ReactElement first and render it accordingly:
// wallet.tsx
...
const additionalProps = { ... };
if (React.isValidElement(children)) {
return React.Children.map(children,
(child, i) => React.cloneElement(child, { key: i, ...additionalProps });
} else {
// handle null, strings, undefined, booleans etc
return typeof children === 'function' ? children(additionalProps) : children;
}
...
// index.tsx
<Wallet ...>
{/* either a function */}
{(additionalProps) => console.log(additionalProps)}
{/* or components */}
<Layout>
...
</Layout>
</Wallet>
Note that React.isValidElement()
also returns true for HTML-Elements. Which will receive the props but you obviously cannot add custom-logic. But let's say you pass a style
props, it will be applied.
Upvotes: 0
Reputation: 604
I guess the error may not be in the destructuring, but in how you are using childrenWithProps
.
It would be useful if you shared a condesandbox representing the problem with dummy data, so we can take a look there at that part too.
Upvotes: 1