Global State with React Hooks
Tags: javascript, react, state, hooks
Published: 2019-06-08 03:55:45

_Read the original article [here](https://rahmanfadhil.com/global-state-hooks)_

[React Hooks](https://reactjs.org/docs/hooks-intro.html) let you use state and other React features in functional components. On the other hand, [React Context](https://reactjs.org/docs/context.html) provides a way to pass data around components tree having without pass props down manually.

With both features combined, we can now build our very own state management without using third-party libraries. Besides making our web applications lighter, our code is much more efficient and readable.

## Disclaimer

First disclaimer, these methods are not the best practice to manage global state (use [Redux](https://redux.js.org/) instead). Second, there some third party libraries out there that are similar to what we are doing in this tutorial. If those are what you're looking for, definitely check out something like [Unstated Next](https://github.com/jamiebuilds/unstated-next) or [Easy Peasy](https://github.com/jamiebuilds/unstated-next).

## What we're going to build?

We are going to build a simple counter app which just increases a number by clicking a button. Our state management system will look like Redux (using reducer function and dispatcher). Finally, we're going to be able to scale up our app by merging two (or more) reducers functions (part 2).

I have published a completed version of this project right [here](https://codesandbox.io/s/globalstatehooks-g8gru?fontsize=14).

## Global state hook

```js
// ./useGlobalState.js

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

const StateContext = createContext(null)

export function Provider({ children, reducer, initialState }) {
  return (
    <StateContext.Provider value={useReducer(reducer, initialState)}>
      {children}
    </StateContext.Provider>
  )
}

export function useGlobalState() {
  return useContext(StateContext)
}
```

Our state management is very straight forward. We store our **entire** state inside our `StateContext` context, then we have a `Provider` component which we will use later to provide our global state to make all components inside our component tree can access it.

Finally, we define our `useGlobalState` custom hook which we will use inside our components where we want to access our global state.

## Providing state

We have our state management ready, now we need to create our state and provide it inside `App` component.

First thing first, we declare our reducer function to mutate our state. At the moment, we only able to handle `INCREMENT` action to increase our counter state.

```js
function reducer(state, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1
    default:
      return state
  }
}
```

You notice that we change our state by returning a new value. That's because our state is immutable, we can't change our state by reassigning new value. That is one important thing to keep in mind when using `useReducer`.

Then, we need to define our initial state. Our counter app should start by 0.

```js
const initialState = 0
```

Finally, our `App` must provide our state with `Provider` component to make other components inside our component tree can access it. `Provider` component requires reducer function and an initial state as props. Let's both of them as we defined earlier.

```jsx
export default function App() {
  return (
    <Provider reducer={reducer} initialState={initialState}>
      <Counter />
    </Provider>
  )
}
```

If you've done it right your code should be look like this.

```jsx
// ./App.js

import React from "react"

import { Provider } from "./useGlobalState"
import Counter from "./Counter"

function reducer(state, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1
    default:
      return state
  }
}

const initialState = 0

export default function App() {
  return (
    <Provider reducer={reducer} initialState={initialState}>
      {/* Place your components here */}
    </Provider>
  )
}
```

## Accessing global state

To test our state works, let's try to access our global state from `Counter` component.

```jsx
// ./Counter.js

import React from "react"
import { useGlobalState } from "./useGlobalState"

export default function Counter() {
  const [state, dispatch] = useGlobalState()

  return (
    <div>
      <h1>Counter: {state}</h1>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>Increase</button>
    </div>
  )
}
```

In this component, we display our state inside an `h1`. We're trying to call `INCREMENT` action whenever our "Increase" button has been clicked.

Try to run the app. If you don't see any error, you followed this tutorial correctly.

Here is the code of this project:

{% codesandbox globalstatehooks-g8gru %}