Pass Props Through Multiple Levels With React's Context API

Dave Ceddia
InstructorDave Ceddia
Share this video with your friends

Social Share Links

Send Tweet

Threading props down through a bunch of components that don't care about them is not only sad, but it also tightly couples those components to their locations in the hierarchy.

React 16.3's Context API makes it possible to pass props down multiple levels invisibly, behind the scenes, and gives you new ways to organize your data.

This lesson covers how to take a React app with multi-level "prop drilling" and refactor it to use the Context API. We also cover how to create a context provider component to contain related state, and keep it abstracted away from other parts of the app.

Instructor: [00:00] The root component here is called app. It has one piece of state, it's this user object with an avatar, name and some data. You can see you have the avatar is used in two places, the one in the navbar and the one in the sidebar here.

[00:13] To get the data where it needs to go, app needs to pass the user as the prop to nav into body, and body has to pass the user along to sidebar. Finally, sidebar takes the user and passes it to user stats which displays it.

[00:30] The body and sidebar in nav components don't actually need this user at all. They just have to take the prop and pass it along to their children. This isn't great, because it makes the components timely couple to where they are in the app tree and it makes them hard to use and hard to move around.

[00:46] We can fix this with React16.3's context feature. To use it, we can create a new context. We'll call a user context. Then, we use React.createContext to create it. This returns an object with two properties, one called provider and the other is called consumer, which we can access with UserContext.Provider and UserContext.Consumer.

[01:09] To use this now, we can wrap our component tree with the UserContext.Provider. We need to pass a single prop called value. We'll pass in our user object here. This provider makes its value available to every component in a tree underneath it.

[01:27] Not just the nav and body, but their children and grand children as well. Now, we can use the consumer to extract the value from the context and use it where we need. Up here, we have user avatar and user stats. Both of them currently take a user prop.

[01:44] Instead of the prop, we're going to wrap the component in a UserContext.Consumer. We get this error that renders not a function, because consumer expects that its single child is going to be a render function. This is called the render props pattern.

[02:00] It is a pretty powerful way of composing components together. We'll get the user here which is actually the value that we passed in to the provider down here. Now, this function is responsible for rendering the output. Now, we're getting user from the context.

[02:16] We don't need the prop anymore. If we save, we'll see that the stats is still working. Let's do the same thing to the avatar. Again, the other we have user from context, we don't need it as a prop.

[02:33] Now then, we have the context wired up. We can go through all the components that don't need the user anymore. Then, delete it. We're deleting it for now. We don't need it in sidebar anymore. We don't need to pass down the user stats and the body doesn't need it and it doesn't need to pass along, and the app doesn't need to pass it now for body either.

[02:57] We could take this one step further by turning the user provider into its own component, so where we have app right now, we can call this user provider, because it has the state and passes the state down already.

[03:11] Instead of rendering this app content, we would just render as the children prop. Now, app can be a stateless component, so we can make in your app component which just renders what is use to render, and down here at the root of the app, we can wrap the entire app in user provider.

[03:29] When we save everything is the same, because now the user provider is passing things down through the app, and the app doesn't need to know anything about the user object at all.