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:
typescript
function 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:
typescript
function 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.
typescript
function 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.
typescript
function App() {return (<Router><Route path="/users" element={<UserList />} /></Router>);}
Performance-wise, this pattern is exciting...
Let's consider the following code below:
typescript
function 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
UserList
element updates due to its state updating, do theUserItem
elements 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.
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