State Management in React 16.8

As Patrick told you in his post back in April we recently switched to React as our primary web development framework because we decided that it looks like the most promising technology at the moment. The reasoning behind this decision and how we intend to implement state in our projects from now on are outlined below.

Some of our mobile development is done using React Native and by switching to React we created knowledge synergies between our web and mobile teams. We initially used MobX to manage state in our applications but with the release of Hooks in React 16.8 we decided to drop MobX and switch to vanilla React state management using the Hooks and Context APIs.

Why Did We Drop MobX?

While MobX is an amazing framework to manage state in React applications, it’s implementation is based on class components which are incompatible with the newly introduced Hook API. In our opinion, Hooks bring incredible
improvements on how you can write reusable logic and reduce the complexity of your codebase. It’s also suggested by the React developers that Hooks are the way to go forward and that future components should be built upon this API. These and other reasons led to our decision to drop MobX and move on to fully embrace Hooks in our projects and use React’s own systems for state management.

It should be noted that there’s a dedicated MobX Lite implementation that supports Hooks
and adds additional state management functionalities on top of it but we saw no big benefit
in these so we decided to go with the API that React provides out of the box.

Hooks

There are many amazing parts of the new Hooks API such as Effect Hooks to encapsulate side effects, Context Hooks that integrate the context system into the new API, memorization hooks for callbacks and values and more. It’s beyond the scope of this post to go into details on all of the different Hooks so we’ll focus on those that are most useful to manage state, the State and the Context Hooks.

State Hooks are the next iteration on how local state was managed in React before the addition of Hooks. The whole functionality of State Hooks can be accessed with the following one line of code:

const [value, setValue] = useState( 42 );

The only parameter of the function is the initial value the state should be initialized with. The returned array can be destructured to receive the current value of the state as the first element and a function to modify the state as the second one. This gives us everything we need to manage the local state of our components and it’s the equivalent to the state and setState members of class components but can also be used in function components.

Context

There comes a time in every project where you have to incorporate some kind of global state even though this should usually be avoided for as long as possible because global state tends to make components much harder to test.

Theoretically, we can already have gobal state by creating state on our root component and passing it through our component tree as props. For small projects this can be a valid strategy but as projects grow it becomes more and more infeasible because even intermediate nodes that just pass props along have to know about the full state potentially needed by their children. This can be avoided by using the Context API which is used to pass data through the component tree. The first step is to create the context:

const UserContext = createContext({name: "Donald Truck" });

The parameter passed to the create method defines the default value that will be used if no other value is provided to a consuming component. The created context alone doesn’t do much. To actually use the context to manage global state we have to create state somewhere in the component tree and provide it to all components farther down.

const [user, setUser] = useState({name: "Doug Obert" });
return (
< UserContext.Provider value= {user} >
<..>
</ UserContext.Provider >
);

We can then access the context from anywhere farther down the component tree. Until Hooks were introduced this had to be done using UserContext.Consumer components but React 16.8 also provides a Context Hook that simplifies accessing the Context: const user = useContext(UserContext);

The received value is the value that’s being provided by the nearest Context Provider up the tree. We can add any properties we like to Contexts so we can also provide functions to modify the global state to consuming components.

Conclusion

This post should’ve demonstrated that state management in React 16.8 can be accomplished without additional frameworks through an API that’s convenient to use and provides lots of functionalities for complex scenarios. We are very excited about the possibilities that come with Hooks and look forward to talk about how they influenced our codebase in the future.