React Design Patterns - Prop Getters & Render Props

May 27, 2019

Render Props are perhaps one of the most underrated design patterns in React. I call it underrated because even developers who have been using React for years do not use this pattern as much as it should to be used.

We're going to continue with our Dropdown component. Flock has many such components, which look like:

App Menu Dropdown
Display Type
User Profile

You might have noticed that all of these components have similar logic - User clicks on a CTA (Call-To-Action) and the Dropdown opens up. When the user clicks anywhere else, the Dropdown closes.

So, what this means is the component's state logic remains the same, however, the content in the component is never the same.

Let's begin with component composition - the most basic version of our component that will solve this problem.

Component Composition

import React, { Component } from "react";
import "./Dropdown.css";

export default class Dropdown extends Component {
  state = {
    show: false
  };

  toggle = () => {
    this.setState(({ show }) => ({
      show: !show
    }));
  };

  render() {
    const { show } = this.state;
    const { children, label, onToggle } = this.props;
    return (
      <div className="dropdown">
        <span className="cta" onClick={this.toggle}>
          {label}
        </span>
        {show ? <div className="content">{children}</div> : null}
      </div>
    );
  }
}
Edit compassionate-pasteur-yy24m

While this does solve our problem at hand, what if we could let our component user decide every detail of the interaction? Enter Render Props.

What are prop getters?

The whole idea of prop getters is to think of React as an extension of JavaScript and the fact that even functions are first-class objects. Would you believe me if I told you that instead of passing down components as children props, you could pass down functions with props as parameters that return JSX?

Too confusing? Let's see it in action.

Implementation:

/* src/Dropdown.js */
import { Component } from "react";

export default class Dropdown extends Component {
  state = { on: false };

  getStateAndHelpers() {
    const { on } = this.state;
    return {
      on,
      toggle: this.toggle,
      togglerProps: {
        onClick: this.toggle
      }
    };
  }

  toggle = e => {
    const { onToggle } = this.props;
    e.stopPropagation();
    this.setState(
      ({ on }) => ({ on: !on }),
      () => {
        const { on } = this.state;
        onToggle(on);
      }
    );
  };

  render() {
    const { children } = this.props;
    return children(this.getStateAndHelpers());
  }
}

Usage:

/* src/index.js */
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Dropdown from "./Dropdown";

import "./styles.css";

function App() {
  const [toggle, setToggle] = useState(false);

  function onToggle(value) {
    setToggle(value);
  }
  return (
    <div className="App">
      <h1>Dropdown Demo</h1>
      <h2>Using Component Composition</h2>
      Dropdown is {toggle ? "shown" : "hidden"}
      <Dropdown onToggle={onToggle}>
        {({ on, toggle, togglerProps }) => (
          <div className="dropdown">
            <button type="button" {...togglerProps}>
              {on ? "Hide" : "Show"}
            </button>
            {on ? <div className="content">This is the toggle-able content.</div> : null}
          </div>
        )}
      </Dropdown>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Edit busy-cookies-pprgq

When do you need to use prop getters?

You can use the prop getters pattern whenever you wish to hand over the rendering responsibility to your component user. It's basically a function that will return with props as parameters and it is the user's responsibility to hook those props up and return proper JSX. In our case, it is the function we pass inside the Dropdown component. You may also want to use it when you've got a lot of component logic but the component is being used in many places.

Conclusion

Prop Getters is a very powerful design pattern in React and ever since Kent C. Dodds came up with it, it has changed the way users have been writing component libraries in React.

Donate