~3 minutes

React Composability Patterns

Let’s say you want to make your React components more composable…that is, components that do a unit of functionality which can then be combined to make a feature specific component tree.

Here are two patterns to keep in mind that I’ve learned through reactjs-training, thanks Ryan and Michael!

Presenter Pattern

The two parts to this pattern are the data and its presentation so its begging for two React components: a DataGetter and a DataPresenter.

Why?

The motivation for doing this should be apparent: we want to separate data from its presentation so we can support multiple presentations easily. Maybe we have a UnorderedListDataPresenter, an OrderedListDataPresenter, and so on.

Implementation

Here’s is how to build it:

const DataGetter = React.createClass({
  render() {
    const { children } = this.props
    const data = [ 1,2,3,4,5 ]
    return children(data)
  }
})

const DataPresenter = React.createClass({
  render() {
    return (
      <DataGetter>
        {data =>
          <ul>
            {data.map((datum) => (
              <li key={datum}>{datum}</li>
            ))}
          </ul>
        }
      </DataGetter>
    )
  }
})

const App = React.createClass({
  render() {
    return (
      <DataPresenter />
    )
  }
})

How does this work?

It works by taking advantage of this.props.children which gets passed into DataGetter. Since we pass in a function, DataGetter calls that function and just shoves in its data.

Back in DataPresenter the function then iterates over the provided data and renders it however it sees fit.

Decorator Pattern

Let’s say you have a parent component that wants to add functionality to its children.

Why?

It can be useful as a way to keep state at the right level of the component hierarchy. If you have to propagate everything down to every leaf component, it increases complexity quite a bit.

Implementation

A bit more code, but the key is React.Children and React.cloneElement

const CleverParent = React.createClass({
  render() {
    const children = React.Children.map(this.props.children, (child) => {
      return React.cloneElement(child, {
        onClick: () => alert(JSON.stringify(child.props, 0, 2))
      })
    })
    return <div>{children}</div>
  }
})

const SimpleChild = React.createClass({
  render() {
    return (
      <div onClick={this.props.onClick}>
        {this.props.children}
      </div>
    )
  }
})

const App = React.createClass({
  render() {
    return (
      <CleverParent>
        <SimpleChild>1</SimpleChild>
        <SimpleChild>2</SimpleChild>
        <SimpleChild>3</SimpleChild>
        <SimpleChild>4</SimpleChild>
        <SimpleChild>5</SimpleChild>
      </CleverParent>
    )
  }
})

How does this work?

It is pretty self-explanatory once you see it, but the idea is the CleverParent makes a copy of its actual children, decorates them with additional functionality not in the markup itself, and then renders those decorated clones.

Of course, the children need to be written to allow this, but this is the general idea.

Hopefully this is useful as you try to make more composable components!

Tagged with: programming

My first novel is coming soon-ish!

Check out Singular