I currently render an array of component as child of another component like this:
const myComponents = [
<div key='1'>Component 1</div>,
<div key='2'>Component 2</div>,
<div key='3'>Component 3</div>,
];
render() {
return (
<AnotherComponent>
{myComponents}
<div>Another element</div>
</ AnotherComponent>
)
}
My issue is that inside AnotherComponent
, my array of components is rendered as an array (which makes sense):
// Inside AnotherComponent
console.log(this.props.children) // [[ {}, {}, {} ], {} ]
My expected output is that components should be "spread", like this:
// Inside AnotherComponent
console.log(this.props.children) // [ {}, {}, {}, {} ]
I have tried to map
the components in the render but the output is the same:
const myComponents = [
...
];
render() {
return (
<AnotherComponent>
{myComponents.map(component => component)}
<div>Another element</div>
</ AnotherComponent>
)
}
I can achieve that with flattening my array of children inside AnotherComponent
. But I was wondering if there was a syntax that would allow me to flatten it before, so that AnotherComponent
is cleaner.
Reason I want to achieve this is because I do some complex layout rendering inside AnotherComponent
. This requires the children not to be arrays, unless I explicitly want it, which is not the case here.
Edit: Here is a demo with my current output and my expected output:
const components = [ <div>Component 1</div>, <div>Component 2</div>, <div>Component 3</div>, ]; const MyLayoutComponent = ({ children }) => { console.log('❌ Current output', children); console.log('✅ Expected output', children.flat()); return <div>{children}</div> } const App = () => ( <MyLayoutComponent> {components} <div>Some other component</div> </MyLayoutComponent> ); ReactDOM.render(<App />, document.body)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.0.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.0.0/umd/react-dom.production.min.js"></script>
The fact that they come through as an array is appropriate, and useful because React can optimize re-rendering if the order of the list changes based on the key
attribute. It's the fact they're in an array that makes React look for a key.
If you don't want them to be a list, per se, you could use a fragment instead:
const myComponents = <>
<div>Component 1</div>
<div>Component 2</div>
<div>Component 3</div>
</>;
That will still come through as a single entry in props.children
, but that entry will be a fragment, not an array, and React won't require keys on it, etc.
The only other answers I can think of are to put your other components in an array as well (but that will require they have a key
):
const App = () => (
<MyLayoutComponent>
{[...components, <div key="other">Some other component</div>]}
</MyLayoutComponent>
);
const components = [ <div>Component 1</div>, <div>Component 2</div>, <div>Component 3</div>, ]; const MyLayoutComponent = ({ children }) => { console.log('✅ Current child count', children.length); console.log('✅ Expected child count', children.flat().length); return <div>{children}</div> } const App = () => ( <MyLayoutComponent> {[...components, <div key="other">Some other component</div>]} </MyLayoutComponent> ); ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.0.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.0.0/umd/react-dom.production.min.js"></script>
Or to ditch JSX for this one case and write the createElement
call directly:
const App = () => React.createElement(
MyLayoutComponent,
{
children: [
...components,
<div>Some other component</div>
]
}
);
const components = [ <div>Component 1</div>, <div>Component 2</div>, <div>Component 3</div>, ]; const MyLayoutComponent = ({ children }) => { console.log('✅ Current child count', children.length); console.log('✅ Expected child count', children.flat().length); return <div>{children}</div> } const App = () => React.createElement( MyLayoutComponent, { children: [...components, <div>Some other component</div> ] } ); ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.0.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.0.0/umd/react-dom.production.min.js"></script>
I can't think of a JSX way to do that.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.