React Composition Patterns From The Ground Up

This post explores the many ways React Components can be combined, mixed-in, and mixed-up, including:

  • The Lifting State & Container/Presenter Pattern

Building Blocks

First, a refresher on the essentials. We’ll start out without any JSX syntactical sugar so we’re clear what’s happening under the hood. Later we’ll explore JSX syntax and compositional techniques.

Elements

A React Element is a virtual representation of an HTML Element that is synced with the real DOM using the render function from react-dom. createElement is a utility to create React Elements.

Arguments to createElement:

  • type: DOM element name ("h1"), or handle to a function that creates elements (see Components below).

Components

Components are functions that return renderable “nodes”: Elements, strings, null, or other Components. Components that extend the React.Component class are more abstract:

  • They must implement a render method that provides the return value as above

Unlike the static example in the Elements section, this HTML will update if Baz changes its state.

JSX

JSX is a syntax that transforms XML-like trees into createElement calls:

Read JSX In Depth and WTF is JSX? for a deep dive into what you can and can’t do with JSX.

Composition Patterns

Lifting State & Container/Presenter

The simplest way to compose React components is to follow these rules:

  1. Divide components into stateful “containers” and stateless “presenters”.

The React docs have a good explanation of how to structure components in this way: Lifting State Up

Higher-Order Component (HOC)

A higher-order component is a function that takes a component and returns a component. One use case is to inject additional props or context.

Think of an HOC as a component factory or a stage in a “component assembly line”.

Without JSX it is technically possible to use HOCs inline as well, but this will cause a re-paint every render because a new component class is created each time and React uses the identity of the component constructor as part of its reconciliation.

Examples

  • React-Redux uses an HOC called connect to map store state to props

Disadvantages

  • Creates a wrapper around components, allocating a new function and taking up space in the tree when debugging

Render Prop/Function-as-Child

Components that use the “render prop” pattern invert control of rendering from the component itself to the consumer by accepting the render function as a prop. This prop is commonly called “render”, although since JSX children are turned into the 3rd argument to createElement, the children prop can be repurposed as a render prop, too (the function-as-child pattern).

See Use A Render Prop and Function as Child Component for an in-depth discussion of the approach.

Note: Render props should be called as plain functions, not components with JSX/createElement. React uses the identity of the component constructor as part of its reconciliation:

❌ Don’t do: const Comp = props.render; return <Comp x={y} />
✅ Do: return props.render(y)

Disadvantages

  • Function signature is difficult to enforce (static checking works, using PropTypes at runtime is impossible)

“Renderless” State Provider

The “renderless” component pattern takes the container-presenter pattern to the extreme and forces state management to be implemented completely separately from render logic. React Powerplug is one library that provides utilities for composing components with this pattern.

DIY Example: The snippet below uses higher-order functions and inheritance to compose state containers with arbitrary stateless components. The combine(Container, Presenter) higher-order function allows components that extend the StateContainer utility class to provide state to stateless functions.

Discuss

Did I miss something? Discuss here:

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store