Improve developer experience for accessing context with a custom React hook

Share this video with your friends

Social Share Links

Send Tweet
Published 5 years ago
Updated 4 years ago

In this lesson, we create a custom hook that wraps the useContext hook and returns its value, as well as more useful error messaging if a context provider is missing. This simple addition brings very elegant ergonomics to access context from any component.

Simon Vrachliotis: [0:00] We have reduced prop reading by putting the list of names in the context provider at the root level of the App and consuming that context in the NamePicker and ShortList components directly. Still, both times we had to import useContext, import the NamesContext itself, then consume it.

[0:18] Let's take it a step further and create a custom React Hook that does this for us with better ergonomics. In the names.js files, we'll export a function called useNames(). This is a custom Hook. In it, we will grab the context like we did before with useContext and return it.

[0:39] I will need to import useContext at the top of the file. Now, a small note before I continue. With our previous setup, let's say we accidentally forgot to wrap the App in the NamesProvider component, the error messaging, while useful, is not immediately pointing us to the right direction.

[0:57] In our custom Hook, let's be more specific. If we couldn't get the context value from useContext, we throw a new error with a message like, "You probably forgot a <NamesProvider> context provider." I can now stop exporting the context, as we won't use it directly in other files.

[1:14] I'll go in NamePicker, remove the useContext import, replace the names context import with useNames and here, replace useContext with useNames. Let's go and ShortList and do exactly the same, and it still works. Now, if we forget to have our context provider wrapper, we get a much nicer error message.

[1:47] Let's do one more thing. This might not always be recommended for reason of performance and re-renders, but as an exercise, let's create another context provider that bundles the state for the search in ShortList to see how it can dramatically clean up our app component.

[2:03] As before, I will import React and createContext. I will also import useState and useContext here. I'll create a context called AppStateContext, and we will export an AppStateProvider() function.

[2:19] In there, before returning our context provider component, we will define both pieces of state we were using before. I'll also create a value object which gathers the two states and their updaters together.

[2:32] Finally, I'll return an AppStateContext.provider with the value and the children. Let's do a custom Hook once again called useAppState, which gets the context and returns it or throws a useful error message.

[2:53] Anything nested within this provider will be able to consume that context value. Time to do some trimming. In App.js, we can go and remove all the remaining props on all components. We can also remove the state definitions and the useState import at the top.

[3:13] Implementing a useAppState hook in the components is pretty straightforward. Let's start with NamePicker. We import useAppState at the top. Since the state values have been named the exact same in the context provider, we can copy whatever props we have passed to the component and get them from useAppState instead.

[3:33] It just works. Let's do the same with ShortList, search, and reset search. The App is working again. Sweet. And, our App component. Look at that.