Render Props, React.createContext, Event Handlers, Lifecycles … But How?
React is introducing a new context API that uses render props. I see a lot of questions come up at workshops, meetups, and on twitter about how to use render props outside of render, like in event handlers and lifecycle hooks.
A year and a half ago, when I was working on React Router v4, I was particularly interested in solving the “deep updates” problem once and for all. I created a library called “react-context-emission” (it later became “react-broadcast”) with a conceptually identical API to the new React Context API:
After using this pattern a bit, I really liked connecting values through context with components and render props, but I struggled to access context values outside of rendering. I was used to getting it from
this.context anywhere in my component. It’s one of the reasons we went back to using the current (old?)
contextTypes API directly in React Router.
This problem is not so hard to deal with though. It took me a while to figure it out for myself. But, once you see it, it’s obvious. Check it out!
Accessing Values in Event Handlers
Just, uh… pass the value into the handler:
Accessing Values in Lifecycle Hooks
The previous pattern doesn’t work for lifecycle hooks since we don’t call the hooks, React does. Here are three patterns I’ve used, so pick your favorite (mine is the last!).
You can get access to the data by creating two components, a container that consumes the context and a second that receives the context as a prop.
Make a Higher Order Component
Maybe you’re already used to decorating components with higher order components. It’s pretty quick to turn a render prop into a higher order component. I don’t like this one very much cause there’s lots of code shuffling and multiple concepts to make it happen.
The Component Component: My New Love
One day I made a component that simply took a function as a prop and called the function in
componentDidUpdate. I’d already been making props named
render and now I had one called
didUpdate. I realized that I could turn every method of a component class into a component prop, and then @reactions/component was born!
It’s really handy to compose render props into lifecycle hooks without all the code shuffling.
It’s common to diff the props in
componentDidUpdate, that works out just fine, too:
That’s my favorite way to deal with it. The code can change and be moved around without friction because it doesn’t introduce new concepts, all composition happens with components. If you no longer need the lifecycles you don’t have to unwind any other abstractions, you just delete the
So there you have it. Obvious when you’ve seen it, tricky when you haven’t.