Carl Rippon

Building SPAs

Carl Rippon
BlogBooks / CoursesAbout
This site uses cookies. Click here to find out more

Render props are still useful

August 28, 2019
reacttypescript

The render props pattern has been a popular way to share logic between components. Since React 16.8 custom hooks are a more elegant way of sharing logic between components. So, no need for render props now then? No! Render props are still useful for building reusable components …

What is a render prop?

A render prop is a prop that is a function that renders something - i.e. a function that returns JSX:

interface Props {
  ...
  renderItem?: (item: string) => JSX.Element;
  renderHeader?: () => JSX.Element;
}

They can be used to delegate the rendering of bits of a component to the consumer of the component. This can make a component very flexible and highly reusable.

Every component already has a render prop!

Every React component has a children prop:

export const Card: FC = ({ children }) => (
  <div className="card">{children}</div>
);

This is a render prop! In the above example the children prop allows the consumer of the component to render the content of the card.

<Card>
  <p>Some interesting text</p>
  <button>Click me</button>
</Card>

Above is an example of consuming the Card component. The paragraph and button elements nested inside Card are picked up as the children prop and rendered inside the card div:

Card

Creating a render prop

We can create our own render prop:

interface Props {
  title?: string;
  renderHeader?: () => JSX.Element;
}
export const Card: FC<Props> = ({ children, title, renderHeader }) => (
  <div className="card">
    <div className="card-header">
      {renderHeader ? renderHeader() : title !== undefined ? title : null}
    </div>
    <div className="card-content">{children}</div>
  </div>
);

We have extended the Card component to have a header. The consumer can override default appearance using the renderHeader render prop:

<Card renderHeader={() => <h3>A custom header</h3>}>
  <p>Some interesting text</p>
  <button>Click me</button>
</Card>

Above is an example of consuming the Card component supplying the header using the renderHeader prop. We simply assign the renderHeader prop to an inline arrow function that returns a h3 containing our title.

Card with custom header

We are now starting to understand the power of render props and how it makes a component super flexible and reusable.

Reusable list

A common use case for render props are list components:

interface Props {
  data: string[];
  renderItem?: (item: string) => JSX.Element;
  renderHeader?: () => JSX.Element;
}
export const List: FC<Props> = ({ data, renderItem, renderHeader }) => (
  <div className="list">
    <div className="list-header">{renderHeader && renderHeader()}</div>
    <ul>
      {data.map(item => (
        <li key={item}>{renderItem ? renderItem(item) : item}</li>
      ))}
    </ul>
  </div>
);

Above is a simple List component that has render props for the list header and list items. Notice that renderItem has a parameter for the data item to be used when rendering the item.

<List
  data={["Fred", "Bob", "Jane"]}
  renderHeader={() => <h3>Names</h3>}
  renderItem={item => (
    <div>
      <span style={{ marginRight: "10px" }}>{item}</span>
      <button>Click me</button>
    </div>
  )}
/>

Above is an example of consuming the List component. We render the list header using a h3 using the renderHeader prop. We render each data item in a span with a “Click me” button alongside it using the renderItem prop. Below is the result:

List

Nice!

Wrap up

Render props are still really useful when we are creating highly reusable components that allow the consumer to render custom elements.

Every React component automatically has a children prop for allowing the consumer to render a single bit of the component.

We can create our own render props in a component where we want to allow the consumer to render different bits of a component.

Render props can take in parameters which is useful when the render prop is being used to render a collection of data items.

Did you find this post useful?

Let me know by sharing it on Twitter.
Click here to share this post on Twitter

If you to learn more about using TypeScript with React, you may find my course useful:

Using TypeScript with React

Find out more