The Children Prop Pattern in React
While it is one of the most underused patterns in React, the Children Prop Pattern is a powerful tool for building reusable components. But it has another aspect that makes it even more interesting to understand and use: re-renders optimization.
4 min read - 781 words
The Children Prop Pattern is the most underused and underappreciated pattern in React. It's the only pattern that matters. For two reasons
Look at the code below:
typescriptfunction Container() {return (<div className="container"><UserList /></div>);}function UserList() {return (<div className="user-list"><UserItem /><UserItem /><UserItem /></div>);}
We can see that the UserItem elements do not depend on any local variables
inside the UserList component.
It is a perfect candidate for the children prop pattern.
To use the children prop pattern, we rewrite the above code to move the
UserItem elements above in the tree and add a children prop to the
UserList component. It gives us the following:
typescriptfunction Container() {return (<div className="container"><UserList><UserItem /><UserItem /><UserItem /></UserList></div>);}function UserList({ children }: { children: React.ReactNode }) {return <div className="user-list">{children}</div>;}
The children prop is a special prop in React: React automatically populates
it with the content between the opening and closing tags of the component.
The children prop pattern is a form of composition. It allows you to compose components together. It allows you to build complex components from simpler ones.
It improves the readability and maintainability of your code. You can avoid props drilling with this pattern and even prevent using the Context API.
Short answer, no.
As I said above, this pattern only works when the children's elements do not depend on their parent component's internal variables.
For instance, we cannot rewrite the following to use this pattern. The
div element and the UserItem elements depend on the selected variable.
typescriptfunction UserList() {const [selected, setSelected] = React.useState(0);return (<divclassName={classnames("user-list", {"has-selection": selected !== null,})}><UserItem selected={selected === 0} /><UserItem selected={selected === 1} /><UserItem selected={selected === 2} /></div>);}
children prop name?The children prop pattern does not limit itself to the children prop name.
You could use any name to pass down elements like kids or element.
The only difference for the children prop is that you have the tree syntax
offered by JSX.
For instance, the React Router library uses the element prop name to pass
down elements.
typescriptfunction App() {return (<Router><Route path="/users" element={<UserList />} /></Router>);}
Performance-wise, this pattern is exciting...
Let's consider the following code below:
typescriptfunction Container() {return (<div className="container"><UserList><UserItem /><UserItem /><UserItem /></UserList></div>);}function UserList({ children }: { children: React.ReactNode }) {const [count, setCount] = React.useState(0);return (<div className="user-list"><button onClick={() => setCount(count + 1)}>Click me</button>{children}</div>);}
Before continuing below, can you answer the following question:
when the
UserListelement updates due to its state updating, do theUserItemelements re-render?
I'll let you think about it for a moment.
The answer is no. The UserItem elements will not re-render because they are
not part of the UserList component tree. They are part of the Container
component tree.
When the UserList component updates, it uses the prop children to render
its content. The children prop is stable between UserList re-renders due to
count state updates. It is the same reference, object, in short elements. So
the React reconciliation algorithm will not re-render the UserItem elements.
Yes, you read it right, the children prop is not re-rendered
when the component re-renders : the prop children comes from outside the component.
Do not believe me ? Try it in this CodeSandbox.
If you check the Profiler tab, you will see that the UserItem elements are not
re-rendered when the UserList component re-renders.
That is why I say that a component re-renders when the parent that
instantiates it re-renders. In our case, the parent of the UserItem
elements is the UserList component, but the parent that instantiates them is
the Container component. So the UserItem elements will re-render when
the Container component re-renders.
Take a moment to think about this in terms of performance.
With this article, you should now understand how powerful the Children Prop Pattern is and how it can help you improve your codebase and components.
Did you like this article? Don't hesitate to share it or leave a comment below 🙂.
Exploitez des données serveur rapidement
Maîtrisez le développement d'applications complexes avec React
Understanding React Hooks: JavaScript Fundamentals
All you need to know about React.useState