Reputation: 3592
I have a component where I receive props that include a Link component (of React router, but could be anything):
children: [
{
id: '1',
isActive: false,
label: 'Forms',
icon: <DestinationsIcon height={30} width={30} />,
link: <Link to={'somewhere'} />,
},
Then in the component receiving those props I can extract the props form the children:
<List>
{React.Children.map(children, (child) => {
if (!React.isValidElement(child)) {
return null;
}
return React.cloneElement(child, {
children: <div>{child.props.label}</div>,
});
})}
</List>
The child.props.label
does return the correct label for example. However what I'd like to do is replace that wrapping <div>
with the link
props, something like this:
children: <child.props.link>{child.props.label}</child.props.link>,
This of course doesn't work. If I'm trying with React.createElement:
children: React.createElement(child.props.link),
The first argument should be a string, but I'm passing a component. The thing is that I must receive the Link component from outside with its own context, and I cannot re-create it, otherwise I could avoid all the complexity.
Does anyone know what would be the correct way to render that link props as a JSX wrapper?
Upvotes: 0
Views: 192
Reputation: 1074335
Your link: <Link to={'somewhere'} />
prop isn't a component, it's an element. This is what it would look like as a component: link: Link
(and then you'd need to pass the props for Link
separately, perhaps as linkProps
):
children: [
{
id: '1',
isActive: false,
label: 'Forms',
icon: <DestinationsIcon height={30} width={30} />,
link: Link, // ***
linkProps: {to: 'somewhere'}, // ***
},
Then, to use it, you need to be referencing it via an identifier with an upper case first character, since that's how React/JSX differentiate between tags (like div
or svg
) and components.
So something along these lines:
const Link = child.props.link;
return React.cloneElement(child, {
children: <Link {...child.props.linkProps}>{child.props.label}</Link>,
});
...although that may need tweaking as it's not clear to me why you're doing the extracting and cloning.
Here's a simpler example showing using a component as a prop:
const { useState } = React;
const Example = ({ link: Link, linkProps, label }) => {
return <Link {...linkProps}>{label}</Link>;
};
const SomeNiftyLink = ({ href, className, children }) => (
<a href={href} className={className}>
{children}
</a>
);
const App = () => {
return (
<Example
link={SomeNiftyLink}
linkProps={{
href: "#somewhere",
}}
label="The label"
/>
);
};
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
Upvotes: 2