Skip to content

Component Component

NOTE: This component was developed in the days before React Hooks. In most cases, you should probably build your function components using hooks and use a class component in the rare cases you need them. We may deprecate this component in the future.

A dynamic, functional version of React.Component, a component component if you will. Useful for inline lifecycles and state. It's also incredibly composable and used in many other Reach components.

<Component initialState={{ hue: 0 }}>
  {({ setState, state }) => (
    <div style={{ textAlign: "center" }}>
      <button onClick={() => setState({ hue: Math.random() * 360 })}>
        Generate Triad Colorscheme
      </button>
      <br />
      {[1, 2, 3].map(n => (
        <div
          key={n}
          style={{
            display: "inline-block",
            margin: 10,
            width: "2em",
            height: "2em",
            borderRadius: "50%",
            background: `hsl(${state.hue + n * 120}, 50%, 50%)`,
            transition: "background-color 200ms ease"
          }}
        />
      ))}
    </div>
  )}
</Component>

Installation

npm install @reach/component-component
# or
yarn add @reach/component-component

And then import it:

import Component from "@reach/component-component";

Props

PropType
initialState object
getInitialState func
refs object
getRefs func
didMount func
didUpdate func
willUnmount func
getSnapshotBeforeUpdate func
shouldUpdate func
children func
render func

initialState

Type: object

An object of initial state.

Count is 10

getInitialState

Type: func: () => object

A function to return intitial state. Use this when initial state is computed.

In the following example, Date.now() will not be called every time a parent component causes this component to re-render.

<Component getInitialState={() => ({ now: Date.now() })}>
  {({ state }) => <div>Now is: {state.now}</div>}
</Component>

However, in the next example, Date.now() would be called with every re-render, which is not what we want.

// 😭
<Component initialState={{ now: Date.now() }} />

refs

Type: object

Put any refs you need to keep track of here, stuff like DOM nodes, timers, and subcriptions.

getRefs

Type: func: () => object

Use this when any of your refs are computed.

<Component
  getRefs={() => {
    return {
      input: React.createRef(),
      popupContainer: document.createElement("div")
    };
  }}
/>

didMount

Type: func: ({ state, props, refs, setState, forceUpdate }) => undefined

Called when the component mounts.

Perhaps you want some async data but don't want to make an entirely new component just for the lifecycles to get it:

<Component
  initialState={{ gists: null }}
  didMount={({ setState }) => {
    fetch("https://api.github.com/gists?per_page=5")
      .then(res => res.json())
      .then(gists => setState({ gists }));
  }}
>
  {({ state }) =>
    state.gists ? (
      <ul>
        {state.gists.map(gist => (
          <li key={gist.id}>
            <a href={gist.html_url}>{gist.description || gist.id}</a>
          </li>
        ))}
      </ul>
    ) : (
      <div>Loading...</div>
    )
  }
</Component>

See also React Docs.

didUpdate

Type: func: ({ state, props, refs, setState, forceUpdate, prevProps, prevState }) => undefined

Called when the component updates. See React Docs.

willUnmount

Type: func: ({ state, props, refs }) => undefined

Called when the component will be removed from the page. See React Docs.

getSnapshotBeforeUpdate

Type: func: ({ state, props, refs, prevProps, prevState }) => any

See React Docs.

shouldUpdate

Type: func: ({ state, props, nextProps, nextState }) => bool

Return true to signify the component needs an update, false if it does not. Useful for wrapping up expensive parts of your app without having to refactor to new components.

For example: often you find just one part of your component is expensive to render, maybe because of a large SVG with a dynamic style or two. Rather than pulling the elements out of your component and putting them in a new PureComponent, you can inline a shoudlUpdate check:

See also React Docs.

children

Type: node

Usual React children prop.

Hey, I am the child

Type: func: ({ state, props, refs, setState, forceUpdate }) => node

A render prop callback to provide the stateful parts of your component at render time.


render

Type: func: ({ state, props, refs, setState, forceUpdate }) => node


Todo App Example

Here is a pretty involved example showing just how composable this component is:

  • "App state" containing all todos
  • "Todo state" containing state for a specific todo
  • Updates the document title to the number of todos in the list
  • Optimized todo rendering, avoiding updates if the color has not changed
  • Tracked refs

Todo List

This is kinda weird