React in real life ⚛️ - Simplifying with Context and Hooks
Guido Vizoso
Posted on January 10, 2020
Hi there!
I've been thinking for a while about making a series of post to share some day to day tasks the team and I have been facing. This is the first one.
Not all React apps are the same. Some of them use UI libraries, others doesn't. You can use Next or any SSR, JS or Typescript, REST or GraphQL, and so on. But there's something any of us can't escape and it's state management.
Our site uses a headless CMS to handle dynamic pages and data except for some custom pages with transactional components. This architecture made using Redux a no go because global state wasn't necessary.
The problem
Recently we were assigned a task to develop a custom page that would handle a complex state with user flow, steps, multiple options, statuses and API calls. Using only context would've been a nightmare because it'd have been huge and hard to manage. State per component was also discarded because some things had to be shared between components.
The solution
We came up with an idea to use Context as a global state and custom hooks to populate it via API calls and simplify information to the components.
Step by step of how we did it
1. Our first step is creating our Context
// Context.js
import React, { useState } from "react";
const Context = React.createContext([{}, () => {}]); // Our empty Context ready.
const Provider = props => {
const [state, setState] = useState({
userFlow: {...},
otherData: {...},
aLotOfData: [...]
}); // Our context is a state hook ;)
return <Context.Provider value={[state, setState]}>{props.children}</Context.Provider>;
};
export { Context, Provider };
This Context gives the consumer two values: state, the info, and setState, the method to update that same info.
2. Time to create our custom hooks!
Our goal here is to use the information provided by Context, make the API calls and simplify the data so the components won't have a hard time consuming it.
// hooks/useUserFlowData.js
import { useContext } from "react";
import { Context } from "../Context";
const useUserFlowData = () => {
const [state, setState] = useContext(Context); // Our values from Context
const updateData = name => {
setState(prevState => ({
...prevState,
userFlow: {
...userFlow,
name: name
}
}));
}; // Our methods to update the state
// Now we return only the relevant part of the state for the component and the method to update it
return {
data: state.userFlow,
updateData
};
};
export default useUserFlowData;
3. Consuming the hook from the component
We're ready to use our custom hook from our component. Let's get to it!
// components/UserData.js
import React from "react";
import useUserFlowData from "../../hooks/useUserFlowData";
export default () => {
const { data, updateData } = useUserFlowData(); // Our data and methods
return (
<div>
<span>{data.name}</span>
<button onClick={() => updateData("New Name")}>Update</button>
</div>
);
};
And that's it! Your component is now using a custom hook to get and modify specific data from a huge Context.
Important note: I'm assuming you already have experience with React and Context. Don't forget to wrap your upper most component with the Context Provider
Here's a working example on CodeSandbox:
Conclusion
Thank you very much for scrolling all the way here!
If you like this kind of posts or have any suggestion / idea to improve just let me know.
Also, I'm using Twitter as a dev for the first time so you can follow me at guido_vizoso
Posted on January 10, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.