DEV Community

Cover image for React pattern - Render Props!
Alexandru-Dan Pop
Alexandru-Dan Pop

Posted on • Edited on • Originally published at blog.alexandrudanpop.dev

React pattern - Render Props!

The Render Props pattern is one of the most known React component patterns. It is useful in scenarios where we need to inject dependencies (props) in our components.

What does it solve

We can decouple a provider / logic component from a presentation component.

If I have a Layout component that renders a HomePage or ProfilePage component, I don't want to have it dependent on Page components. So the Layout component doesn't import HomePage or ProfilePage, but the Layout can still pass props to them.

Render props in action

So I can have a Layout component that can render any other component we want. Something like:

<Layout>
  <HomePage/>
</Layout>
// or 
<Layout>
  <ProfilePage/>
</Layout>
// etc
Enter fullscreen mode Exit fullscreen mode

So in this case, Layout is implemented to render children- this way it's able to render any other component inside it:

function Layout({ children }) {
  const [isOpen, setIsOpen] = React.useState(false);
  return (
    <div className="layout">
      <button onClick={() => setIsOpen(!isOpen)}> Menu </button>
      {isOpen && <Menu />}
      {children}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Ok, but we have a problem - the HomePage and ProfilePage components also need to know if the menu is open - for some reason. How do we do that?

function Home({ isOpen }) {
  return (
    <div className="home">
      <h1> Home</h1>
      {!isOpen && <button> Contact! </button>}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

At this point, you are encouraged to spend a few minutes and think about a solution before you scroll down.

Some not so good approaches:
โŒ put isOpen in Redux (it's not really global state)
โŒ use a Context Provider
โŒ use conditional rendering to directly render the Page components in Layout

โœ… The solution

Obviously, refactor our code to use the Render Props pattern.

function Layout({ children }) {
  const [isOpen, setIsOpen] = React.useState(false);
  return (
    <div className="layout">
      <button onClick={() => setIsOpen(!isOpen)}> Menu </button>
      {isOpen && <Menu />}
      {children(isOpen)}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Now when we wrap our components in Layout it looks like this:

<Layout>
  {(isOpen) => <Home isOpen={isOpen} />}
</Layout>
// or 
<Layout>
  {(isOpen) => <ProfilePage isOpen={isOpen} />}
</Layout>
Enter fullscreen mode Exit fullscreen mode

We changed two things:
1) We call children as a function when we render it in Layout and pass the desired props
2) When we render something wrapped in the Layout component - we use the function syntax to render the child component

A render prop is a function prop that a component uses to know what to render (React docs).

Disadvantages of Render Props

Now it's cool to use design patterns, but we need to keep in mind - all design patterns have also disadvantages.

The disadvantage of Render props is nesting - if we overuse it, for example:

<Layout>
  {(isOpen) => 
    <Home isOpen={isOpen} > 
      {(handleSubmit) => <ContactForm submit={handleSubmit}/>} 
    </Home>}
</Layout>
Enter fullscreen mode Exit fullscreen mode

So it is advisable to have it only in one layer, and only when it's actually needed.

Conclusion

Render props is an interesting pattern because we can inject props into components while having our provider component generic - only rendering children.

It's important to know that there are limited scenarios today to use render props, like the one I described above. Some use cases of render props can be refactored to React hooks. So try to consider hooks before trying RP.

๐Ÿ‘‡ Comment below ๐Ÿ‘‡
What are your thoughts on the render props pattern or other React patterns? Do you still use Render props or other older React patterns? Or you are only using React Hooks?

Leave a ๐Ÿงก & ๐Ÿฆ„. For more interesting content also check out my Twitter.

Top comments (0)