DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Using Custom React Hooks to Simplify Complex Scenarios
  • Unleashing the Power of React Hooks
  • In-Depth Guide to Using useMemo() Hook in React
  • Build Your Own Shopping Cart With React Hooks

Trending

  • When One MVP Is Really Four Systems: A Better Way to Plan Multi-Role Apps
  • Build a GitHub Slack Bot With AWS Bedrock and MCP, Part 1
  • Chaos Engineering Has a Blind Spot. Agentic AI Lives in It.
  • Why DDoS Protection Is an Architectural Decision for Developers
  1. DZone
  2. Coding
  3. JavaScript
  4. Implement Redux-like Global Store With React Hooks and React Context

Implement Redux-like Global Store With React Hooks and React Context

Introducing a new way to implement a global store step by step by using React Hooks and React Context. The example code is available in GitHub.

By 
Kunkka Li user avatar
Kunkka Li
·
Oct. 05, 20 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
10.2K Views

Join the DZone community and get the full member experience.

Join For Free

In this article, I'm going to introduce a new way to implement a global store step by step by using React Hooks and React Context. The example code is available in GitHub.

1. Initialize the Project

Let's create the project and install the dependencies.

npx create-react-app react-context-hooks
yarn install
yarn start

2. Local Store(state)

Let's illustrate React local store in a simple counter-example. There is a local state to manage the count variable, and a method — setCount to update it. It's quite straight forward, however it's restricted within the component to update count. What if we need to update from other components? React provides Context to achieve that.

JavaScript
 




x


 
1
import React, { useState } from 'react';
2

          
3
function Counter() {
4
  // Declare a new state variable, which we'll call "count"
5
  const [count, setCount] = useState(0);
6

          
7
  return (
8
    <div>
9
      <p>You clicked {count} times</p>
10
      <button onClick={() => setCount(count + 1)}>
11
        Click me
12
      </button>
13
    </div>
14
  );
15
}



3. Global Store(state)

First of all, you need to walk through a basic tutorial for React Context. In a nutshell, React Context provides a way to pass data through the component tree without having to pass props down manually at every level.

3.1 ContextProvider

We define a count state and pass the value to the global context so that its descendants can access count and setCount. As you can see, we use React hooks API: useContext. If you’re familiar with the context API before Hooks, useContext(CounterContext) is equivalent to static contextType = CounterContext in a class, or to <CounterContext.Consumer>. We also create a provider for its descendants to consume and subscribe to changes.

JavaScript
 




x


 
1
import React, {useState, createContext, useContext} from "react";
2

          
3
export const CounterContext = createContext();
4

          
5
export const CounterProvider = props => {
6
    const [count, setCount] = useState(0);
7

          
8
    return <CounterContext.Provider value={[count, setCount]} {...props} ></CounterContext>;
9
};
10
export const useCounterStore = () => useContext(CounterContext);



3.2 Consume Context

We'll create two components called counterview and countercontroller to display and update the count variable in the global store, which will leverage useCounterStore function.

CounterView:

JavaScript
 




xxxxxxxxxx
1
11


 
1
import React from "react";
2
import {useCounterStore} from "../../store";
3

          
4
export default function CounterView() {
5
    const [count] = useCounterStore();
6

          
7
    return (
8
        <p>You clicked {count} times</p>
9
    );
10
}
11

          



CounterController:

JavaScript
 




xxxxxxxxxx
1
12


 
1
import React from "react";
2
import {useCounterStore} from "../../store";
3

          
4
export default function CounterController() {
5
    const [count, setCount] = useCounterStore();
6

          
7
    return (
8
        <button onClick={() => setCount(count + 1)}>
9
            Click me
10
        </button>
11
    );
12
}



Main app:

We just need render CounterView and CounterController as the children of CounterProvider so that they can consume the Context.

JavaScript
 




x



1
import React from 'react';
2
import logo from './logo.svg';
3
import './App.css';
4
import {CounterProvider} from "./store";
5
import CounterView from "./components/counterview";
6
import CounterController from "./components/countercontroller";
7

          
8
function App() {
9
  return (
10
    <div className="App">
11
      <header className="App-header">
12
        <img src={logo} className="App-logo" alt="logo" />
13
        <CounterProvider>
14
          <CounterView />
15
          <CounterController />
16
        </CounterProvider>
17
      </header>
18
    </div>
19
  );
20
}
21

          
22
export default App;
23

          



4. Further Example: userReducer

In this chapter, we will move forward to a more complicated example in which React Context works together with useReducer API to achieve Redux-like global store. If you are not familiar with Redux,  please check my article - https://dzone.com/articles/how-to-build-a-single-page-ui-application-by-using.

4.1 Actions

We define two actions to manipulate the global store: increase and decrease

JavaScript
 




xxxxxxxxxx
1


 
1
export const increase = value => ({type: "increment", value: value});
2

          
3
export const decrease = value => ({type: "decrement", value: value});



4.2 Reducers

I prefer to use the generic way to define reducers, but you also can see the commented code below which is more direct.

JavaScript
 




x


 
1
const initialState = {count: 0};
2

          
3
// function counterReducer(state, action) {
4
//     switch (action.type) {
5
//         case 'increment':
6
//             return {count: state.count + action.value};
7
//         case 'decrement':
8
//             return {count: state.count - action.value};
9
//         default:
10
//             throw new Error();
11
//     }
12
// }
13

          
14
const increment = (state, { value }) => ({
15
    count: state.count + value
16
});
17

          
18
const decrement = (state, { value }) => ({
19
    count: state.count - value
20
});
21

          
22

          
23
const createReducer = (handlers) => (state, action) => {
24
    if (!handlers.hasOwnProperty(action.type)) {
25
        return state;
26
    }
27
    return handlers[action.type](state, action);
28
};
29

          
30
const counterReducerHandler = {
31
    increment, decrement
32
}
33

          
34
export const CounterReducer = [createReducer(counterReducerHandler), initialState];



4.3 Global Store: useReducer Together With React Context

As you can see from the code, the only difference to chapter 3 is to bind useReducer to the context provider. So it would be straight forward to understand the code.

JavaScript
 




x


 
1
import React, {createContext, useContext, useReducer} from "react";
2
import {CounterReducer} from "../reducers";
3
4
export const CounterContext = createContext();
5
6
export const CounterProvider = props => {
7
    const [state, dispatch] = useReducer(...CounterReducer);
8
9
    return <CounterContext.Provider value={[state, dispatch]} {...props} />;
10
};
11
12
export const useCounterStore = () => useContext(CounterContext);
13



4.4 Access to Global Store and Dispatch Actions

There is a slight difference to chapter 3. We can access the state and dispatch by using useCounterStore,

CounterView:

JavaScript
 




xxxxxxxxxx
1
11


 
1
import React from "react";
2
import {useCounterStore} from "../../store";
3

          
4
export default function CounterView() {
5
    const [state] = useCounterStore();
6

          
7
    return (
8
        <p>You clicked {state.count} times</p>
9
    );
10
}



CounterController:

JavaScript
 




xxxxxxxxxx
1
19


 
1
import React from "react";
2
import {useCounterStore} from "../../store";
3
import {increase, decrease} from "../../actions";
4

          
5
export default function CounterController() {
6
    const [, dispatch] = useCounterStore();
7

          
8
    return (
9
        <div>
10
            <button onClick={() => dispatch(increase(1))}>
11
                Increase me
12
            </button>
13
            <button onClick={() => dispatch(decrease(1))}>
14
                Decrease me
15
            </button>
16
        </div>
17
    );
18
}


react-context-hooks

React (JavaScript library) Hook JavaScript

Published at DZone with permission of Kunkka Li. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Using Custom React Hooks to Simplify Complex Scenarios
  • Unleashing the Power of React Hooks
  • In-Depth Guide to Using useMemo() Hook in React
  • Build Your Own Shopping Cart With React Hooks

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook