React projects can get out of hand quickly. You take a component and from it create sub-components. Each of those sub-components get refactored into sub-sub-components. Before you know it, your component tree is several levels deep. You have to pass your state values and functions all the way down the tree.
The resulting code is cluttered and hard to understand if you didn't write it. It's easy to make a mistake when you're passing your props between components. Furthermore, components are aware of state values and functions they are not making use of.
Fear not, there is a solution: the useContext hook! This React hook allows you to wrap your app in a global context. All child components of this context can access your global values and functions directly without the need for prop drilling.
This hook allows you to write clean code with uncluttered components. It allows you to group all your app-wide state values and functions together making it easier to debug. The best part is its very easy to implement. It uses a lot of boiler plate code so it doesn't slow down the development process.
The following example is incredibly simple. I've built contact list app. It displays the name, phone number, and email address of the current contact. There is a list of all contacts. The list contains the name and a button. When you click the button, the current contact is updated.
NOTE: the component tree for this app is so small there is no reason to use useContext. It's just for educational proposes.
Let's refactor using the useContext hook. First, we create a new file. I named mine context. Next, we need to create a context object. To do this, invoke React.createContext or import createCreate context and invoke createContext. Capture the return object in a variable. I called mine AppContext.
Then, create a component that you will wrap around your app. I called mine AppProvider. Pass {children} in as an argument. This component will return an .Provider component. Since I called my context AppContext, it will return an AppContext.Provider component. Wrap the AppContext.Provider component around {children}.
Add a value attribute to component. Inside the curly braces, open up another set of curly braces. This is where you will add your app-wide state values and functions.
Lastly, create a custom hook that will be called in each component. It will return the object inside the value attribute. I called mine useGlobalContext. The only naming rule is the name must start with the word use. To return the object containing the global properties, invoke React.useContext or useContext (don't forget to import if you choose the latter). Pass in the context object you created earlier in the file.
In your index.js file, import AppProvider component. Wrap your app in an AppProvide component.
Now, you can move all of your state values and functions out of your components and place them in the context file before your return statement. Add them to the object contained in the value attribute (make sure there are double curly braces, one to switch to javascript and one to open up an object).
In your component, you get access to these global properties by importing your custom hook. Invoke it inside the function and use object restructuring to grab the properties the component needs. Now just remove all the prop drilling from the application and it should function as intended. The refactored project follows.
Big shout out to John Smilga at Coding Addict (https://www.youtube.com/channel/UCMZFwxv5l-XtKi693qMJptA). He taught me everything I know about React and Redux. Check out his YouTube channel and Udemy page for all his videos.
Top comments (0)