DEV Community

gortron
gortron

Posted on

React: making a store from createContext and useReducer

Introduction

For all but the simplest applications or static sites, React developers will use state to manage data. Determining the optimal location for state is part of the job of a React developer. Is this data relevant only to this component? This container? Or the entire application? Tools like Redux are popular solutions for managing 'global' state for JS frameworks like React.

There are advantages to using Redux (including its documentation, developer tools, and user base), but in this post I'll share an approach that uses existing React tools to make a state container. Specifically, this approach uses createContext and useReducer to make a StateProvider.

Approach

First, we'll write our reducer and store in a store.js. Note that the switch for your actions will look different from mine, but the pattern should look similar.

import React, { createContext, useReducer } from "react";

const initialState = { mobile: true, projects: null, checkout: null };
const store = createContext(initialState);
const { Provider } = store;

const StateProvider = ({ children }) => {
  const [state, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      case "addToCart": {
        return { ...state, checkout: action.payload };
      }
      default: {
        throw new Error(`Unhandled action type: ${action.type}`);
      }
    }
  }, initialState);

  return <Provider value={{ state, dispatch }}>{children}</Provider>;
};

export { store, StateProvider };

Next we'll wrap our application with our StateProvider, to subscribe our Store to that App's view. In your index.js, your code could look like this:

const app = (
  <StateProvider>
    <App />
  </StateProvider>
);

Lastly, we'll need a way to dispatch actions from the view to the reducer in the store. Your App container might look like this:

import React, { useContext } from "react";

const App = () => {
  const { state, dispatch } = useContext(store);
  const itemAdded = item => {
    dispatch({ type: "addToCart", payload: { ...item } });
  };
}

Conclusion

I like this pattern for managing global state in React applications, especially simple ones, principally because it reduces the amount of syntactic sugar from mapStateToProps, mapDispatchToDrops, and export default connect(...). I hope this post was helpful to you!

Discussion (0)