React pattern - Render Props!
Tags: react, javascript, webdev
Published: 2020-09-07 06:52:52

---
title: React pattern - Render Props!
description: Learn to use React Render Props pattern
canonical_url: https://blog.alexandrudanpop.dev/posts/react-pattern-render-props-5e75
---

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:

```jsx
<Layout>
  <HomePage/>
</Layout>
// or 
<Layout>
  <ProfilePage/>
</Layout>
// etc
```

So in this case, Layout is implemented to render `children`- this way it's able to render any other component inside it: 
```jsx
function Layout({ children }) {
  const [isOpen, setIsOpen] = React.useState(false);
  return (
    <div className="layout">
      <button onClick={() => setIsOpen(!isOpen)}> Menu </button>
      {isOpen && <Menu />}
      {children}
    </div>
  );
}
```

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? 

```jsx
function Home({ isOpen }) {
  return (
    <div className="home">
      <h1> Home</h1>
      {!isOpen && <button> Contact! </button>}
    </div>
  );
}
```

> 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. 

```jsx
function Layout({ children }) {
  const [isOpen, setIsOpen] = React.useState(false);
  return (
    <div className="layout">
      <button onClick={() => setIsOpen(!isOpen)}> Menu </button>
      {isOpen && <Menu />}
      {children(isOpen)}
    </div>
  );
}
```
Now when we wrap our components in Layout it looks like this:
```jsx
<Layout>
  {(isOpen) => <Home isOpen={isOpen} />}
</Layout>
// or 
<Layout>
  {(isOpen) => <ProfilePage isOpen={isOpen} />}
</Layout>
```

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](https://reactjs.org/docs/render-props.html)).

## 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:
```jsx
<Layout>
  {(isOpen) => 
    <Home isOpen={isOpen} > 
      {(handleSubmit) => <ContactForm submit={handleSubmit}/>} 
    </Home>}
</Layout>
```
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](https://twitter.com/alexandrudanpop).