If you have state that needs to exist throughout your application, then you may find yourself passing props all over the application and even "drilling" the prop through components that don't really care about the prop at all. In this lesson, we'll see a sample of a small app that has the "prop drilling problem" and learn how to implement the "Provider pattern" to access context state anywhere in the component tree.
Instructor: [00:00] Now, we're using this toggle component in a little app. This app has some navigation. It also has this article here. It has our switch component with enable emoji. If I click on that, then a whole bunch of our stuff turns into emoji, which is pretty cool.
[00:17] How does this work? The way that we do is, in the root level of our app, we'll have the toggle component. Then, we take the toggle utilities and state that we have from here. We render the rest of our app, passing along this toggle.
[00:32] While this is cool, the actual implementation is not. You're going to see a lot of toggle equals toggle all over the place. It's not very fun. In anywhere that needs to use the toggle, it's going to have to accept that as props.
[00:48] Finally, we do have the nav switch which accepts the toggle. It is able to get the toggler props which will add the on click handler and everything that we need to actually interact with the state.
[01:01] We're referencing this toggle all over our app. We have to drill our props all over the place just to get the state to the place it needs to be to accomplish this cool emoji effect. This prop drilling isn't really a huge problem in a small application like this, but it quickly becomes unwieldy. We're going to solve this problem by using a new component that we'll create called a provider.
[01:23] We'll create a new component called toggle provider. This toggle provider is going to take the children it's given. It's going to just simply render those. Then, it'll take the remaining props from this.props. We're going to return our own usage of the toggle component. We'll spread the remaining props over that and specify a render prop. This will accept the toggle state and utilities.
[01:49] It will render another component that will be responsible for setting up the context for this toggle state. We'll put that on the toggle provider and call it renderer. We'll pass along the toggle state, and helpers and the children.
[02:04] Let's go ahead and define a static renderer that is a class that extends react.component. This will have a render function that's pretty simple. It just returns this.props.children, because its job is simply to establish the context. We'll say static child context types equals an object that has toggle provider.context name, which we'll declare as a static member here.
[02:34] Context name, we'll just call it toggle something that's pretty unique, hopefully nobody will clash with that. We'll assign this to prop types.object.is required. We'll define get child context will return an object with toggle provider.context name this.props.toggle. Great.
[02:58] Now, we have this component called toggle provider that's able to take a toggle, put the toggle object in context, and now we need to create a component to get that toggle object out of the context. This one will be pretty simple.
[03:11] It'll just be a function called connected toggle. That'll take props and context. It'll return props.render. This will be a render prop. We'll get out of context toggle provider.context name. To tell React that we want the toggle provider context, we'll say connected toggle.context types equals this object with toggle provider.context name and prop types.object.is required.
[03:43] Now, I'm going to take this toggle provider component and wrap my entire app inside the toggle provider. We'll need to do a little bit of refactoring. Instead of a toggle here, the toggle provider is going to rendering our toggle. We'll get rid of that and that. We no longer need to pass along the toggle here. We only need to go to the places that are using the toggle.
[04:08] If we go to the post, we see that nobody's actually using the toggle. We're just forwarding it along. We'll get rid of this and that. Here in the article, we are using toggle. Rather than getting toggle from props, we're going to get it from our connected toggle component, which accepts a render prop. That's going to get us our toggle. Then, we can put this inside of here. That'll do it for us.
[04:32] Now, I saved it. It blanked out my screen. That's because things are all messed up now. I'm going to have to do a little bit more refactoring. Let's continue on here.
[04:40] We'll take this out. We'll use our connected toggle, and our article is done. Now, let's look at the title. We're not going to get toggle from props anymore. We do need it right here. We can do connected toggle. Cool. Then the subtitle. We can get rid of toggle here. We'll return connected toggle. Header is not using the toggle at all. We can get rid of that and get rid of these. No more prop drilling for us.
[05:12] Now, switch is using the toggle. We'll get rid of the prop. We'll say connected toggle and returns what it had before. The switch will also need to get the connected toggle. Finally, our nav, it won't get toggle from the props anymore. We'll wrap all of this in connected toggle with render.
[05:33] It looks like I missed this. We don't need to forward on the toggle to subtitle anymore. Great. With that refactor, everything is working just fine. We no longer need to drill props all over the app. We can just reach into context with this connected toggle component to get and manipulate the state of the toggle.
[05:52] We made this work by using this toggle provider. This is called the provider pattern. It works by leveraging the context API with child context types and get child context as part of the provider, and a component that allows you to access the context throughout the rest of your application.
[06:10] To do this, we just created a new component called toggle provider. We didn't have to change the toggle component implementation at all. We just leveraged the render prop. When our render prop is rendered, we use a toggle provider renderer that forwards along the toggle and children as a prop.
[06:27] We have this static class defined as part of our toggle provider called renderer which establishes the child context types, renders the children, and provides the child context. We create this small component called connected toggle which allows us to reach into context and get the toggle context.