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.

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

Using TypeScript with React

Using TypeScript with React
Find out more

Want more content like this?

Subscribe to receive notifications on new blog posts and courses

Required
© Carl Rippon
Privacy Policy