React state management using Hooks in Ionic
Tags: react, discuss, javascript, ionic
Published: 2020-11-04 00:55:12


{% codesandbox ftjsc %}

Managing individual states in different components can be cumbersome when your app grows large with time. Hence, we need one central point where you can manage your application state.

Thanks to [Hooks](https://reactjs.org/docs/hooks-reference.html) as they will make our job very easy in setting up the global state. 

Let's get started :sunglasses:

## Step :one:
Set up the state of the application in one single file named `State.tsx` or `State.jsx` (If you're using JavaScript)

```jsx
import React, { createContext, useEffect, useReducer } from "react";
import reducer, { initialState } from "./reducer";

const persistedState = localStorage.getItem("persistedState")
  ? JSON.parse(window.localStorage["persistedState"])
  : undefined;

let AppContext = createContext(initialState as any);

function AppContextProvider(props) {
  const fullInitialState = {
    ...initialState,
    ...persistedState
  };

  let [state, dispatch] = useReducer(reducer, fullInitialState);
  let value = { state, dispatch };

  useEffect(() => {
    window.localStorage["persistedState"] = JSON.stringify({
      loader: state.loader
    });
  }, [state]);

  return (
    <AppContext.Provider value={value}>{props.children}</AppContext.Provider>
  );
}

let AppContextConsumer = AppContext.Consumer;

export { AppContext, AppContextProvider, AppContextConsumer };

```

## Step :two:
Now, we will create a **Reducer** (`reducer.ts`), which is simply a function that takes *previous state* and an *action* and returns the *next state*. 

```jsx
export const initialState = {
  loader: false
};

const reducer = (state, action) => {
  switch (action.type) {
    case "setLoader": {
      return { ...state, loader: action.loader };
    }
  }
  return state;
};

export default reducer;

```
From the above piece of code, there is a `loader` with initial state set to `false`. And, we made our reducer know that whenever an action comes with type `setLoader`, it takes the *previous state* and returns the *next state*.
## Step :three:
Now that we have set up our State and Reducer, our next goal would be to enable state management globally in our application. So, wrap your application inside `AppContextProvider`. In my case, the root of the application is inside `index.tsx` file.

```jsx
ReactDOM.render(
  <AppContextProvider>
    <App />
  </AppContextProvider>,
  document.getElementById("root")
);
```
That's it! We are all set. :rocket:

Let's jump in to an example case where I want to spin and pause a loader. For this, we will be dispatching actions by specifying what action the buttons should perform.

In other words, we will be dispatching the **actions** by specifying the type `setLoader` along with the value you want to pass to the **reducer** - `true` if you want to spin the loader or `false` for pausing the loader.

```jsx
const Home = () => {
  const { state, dispatch } = useContext(AppContext);

  const handleSpinLoader = () => {
    dispatch({ type: "setLoader", loader: true });
  };

  const handlePauseLoader = () => {
    dispatch({ type: "setLoader", loader: false });
  };
  return (
    <IonPage>
      <IonContent>
        <IonSpinner name="crescent" paused={!state.loader} />

        <IonButton onClick={handleSpinLoader}>Spin Loader</IonButton>
        <IonButton onClick={handlePauseLoader}>Pause Loader</IonButton>
      </IonContent>
    </IonPage>
  );
};
```
Whenever you click on the buttons, actions will be dispatched and there by state changes according to the actions.

I created a working example using [Codesandbox](https://codesandbox.io/s/state-management-ionic-react-ftjsc?file=/src/pages/Tab1/Tab1.tsx). Please feel free to check it out and drop your questions or comments if any.
### References
- [A state management pattern for Ionic React with React Hooks](https://ionicframework.com/blog/a-state-management-pattern-for-ionic-react-with-react-hooks/)