React: Creating a ‘Redux-like’ Global State with the useContext and useReducer Hooks

Martin Crabtree
3 min readFeb 13, 2020

--

The introduction of the useContext and useReducer hooks into the React javascript library addresses some of the primary frustrations associated with managing state. For many, this is managing multiple instances of state, and passing information through props to child-components. As an application grows scale and complexity, the process of managing and passing values from state through child-components becomes more complex and error prone, especially if there are significant changes to the application’s architecture.

Enter Redux

Redux was developed by Dan Abramov and Andrew Clark in order to centralize state, and to make the process of manipulating state more consistent. Central to the Redux architecture is the Store, which serves as the single source of truth for an applications state. Manipulating state is handled through the use of Reducers, which are pure functions that carry out an action and then return an updated version of state.

React 16.8.0 Create Your Own Store and Reducers

As of React v16.8.0, we now have access to the useContext and useReducer hooks. For our purposes, the primary benefit of the useContext hook is the ability to reference a Redux-like Store that is house within a global context object that can be created using React.createContext.

useReducer(reducer, initialArg, init)

The useReducer hook accepts two arguments, a reducer function, and an initial value for state.

A reducer function must be able to accept two arguments; the initial value of state, and an action. The action has two properties; the type of action to take, and a payload of data that should be used to update state. The return value of the reducer function is the updated value of state.

The return value of useReducer is the current value of state, along with a dispatch method for the reducer. Invoking the dispatch function requires an object to be passed that specifies the type of action to be executed by the reducer function, and (if needed) a payload that contains any values that the reducer requires to update state.

Putting it all together:

  1. Create a basic reducer for use with useReducer()
Code for creating a simple React reducer.
A basic reducer that updates the username property in the global scope. It accepts two arguments: the current global state; and an action (with the sub properties of type and payload).

2. Create a store that creates a context object that houses a global state. The store acts as a wrapper and propagates the global state to all of the child components. The state and dispatch properties are provided by useReducer(). Dispatch accesses the reducer, and updates global state, which is then returned in the state property (returned from useReducer).

A basic react store using createContext(), and useReducer().
A basic store React component, created using the createContext() function. This provides all child components with access to a global instance of state, which can be updated using a dispatch function provided by useReducer().

3. Adding the store to React web application.

Adding a react store component to a web application (in this case within App.js).
Importing the Store component into App.js, which wraps around all of the child components in the web application.

4. Implementing global state in your React application.

Accessing and updating the global state from inside a react component.
useContext() provides a dispatch function that has been passed down from the Store component. The dispatch function accepts two arguments, a type of action, and a payload for updating the global state. The useContext() function will then return an updated global state.

Sources

https://reactjs.org/

https://redux.js.org/

https://www.robinwieruch.de/react-state-usereducer-usestate-usecontext

https://en.wikipedia.org/wiki/Redux_(JavaScript_library)

https://github.com/facebook/react

https://www.w3schools.com/react/default.asp

--

--