Redux-Toolkit and React-Redux For App-Wide State Management
Tags: react, javascript, beginners, webdev
Published: 2022-07-15 11:07:00

The most important part of any web application is data(state), data that changes and affects how our application works and performs, to effectively use this data we need ways to change it (useState and useReducer) and ways to access it in every part of our application where it is needed.

A little while ago I felt the need the need to learn Redux (such a cool name btw) because it is the standard for state management tools and there a lot of them (trust me I was shocked at how many are in existence). Anyways, I had previously been using the Context API hooks createContext and useContext and they did the job for me, but as your application grows the Context API can get more complex and harder to manage, there is also the issue of performance as your application gets bigger, this is where state management libraries such as Redux/Redux Toolkit come in🦸‍♂️.

![Redux is Hot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wceah867njuxalrhomdk.jpg)

Redux is a cross-component state management system, it aids us in managing and monitoring state without 'props drilling/chaining'(passing state through props in components that have no need for them) and Redux Toolkit is basically just the modern way of writing Redux and hence is the focus of this article.

## HOW DOES REDUX TOOLKIT WORK
Redux Toolkit gives us a central data store (CDS) that handles the state needed application wide, slices of data are stored within the CDS, these slices have unique names, initial data and reducers. slice reducers are functions that alter the state of data in the slice when triggered. The CDS gives components ability to subscribe to the data in the store giving the components access to the data and the components are also notified of any changes made to the data they are subscribed to and they react to the change accordingly, components can also make changes to the store by triggering "actions" in the store through the store's reducers

For this article we will be building a simple counter app aiming at explaining the basic setup and usage of the Redux Toolkit on React apps.

## Create React app

```
npx create-react-app counter-app

```
Your inital file setup will look like this on your IDE

![Initial React set-up](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y0139w2fetokizsy1e9i.PNG)
We'll do a little cleanup of files we don't need and create two new folders in the `src` folder called `components` and `store`, your setup should now look like this..

![new react setup](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gwgxkqcn1nwt5tu1681z.png)

## Installation of packages

We need to install two packages on your React app, the redux toolkit and the react-redux package, react-redux is official React bindings for Redux, react redux is a helper package maintained by the official redux team that helps you manage redux data better, it enables you to easily make connections to the redux store and dispatch actions better, it checks to see if the data your component wants has changed, and re-renders your component, in all react-redux makes life easier when using redux toolkit.

```
npm install @reduxjs/toolkit react-redux 
OR
yarn add @reduxjs/toolkit react-redux

//this installs both packages

"npm run start" to start the application
```

## LET'S BUILD

We'll set up our store folder this will contain our redux store, create a file called `index.js` 

## CREATING THE STORE

```javascript
store/index.js

import { configureStore } from "@reduxjs/toolkit";

const store = configureStore({
  reducer: null,
});

export default store;
```
We make use of the `configureStore` function provided to us by redux toolkit and an object containing the reducer value is passed in as an argument, it creates the CDS (central data store) for us where we store our state slices in the store `reducer`.

## CREATING THE DATA SLICE

createSlice is another function provided to us by redux toolkit, it takes in an object with three properties name, initialState which is the state of the data when the app starts and reducers which are functions that perform some kind of logic for changing the state of the data, when we create a slice redux toolkit automatically generates "actions" object from the data slice corresponding with the reducers names and these actions are what components trigger to make state changes.

```javascript
//  store/index.js

import { configureStore, createSlice } from "@reduxjs/toolkit";

const initialCounterState = { count: 0 };

const counterSlice = createSlice({
  name: "counter",
  initialState: initialCounterState,
  reducers: {
    increment: (state) => {
      state.count++;
    },
    decrement: (state) => {
      state.count--;
    },
  },
});

const store = configureStore({
  reducer: counterSlice.reducer,
});

export const counterActions = counterSlice.actions;

export default store;


```
In the above code we have a counterSlice with a name, initialState and two reducers one for increasing the count by 1 and one for decreasing the count by 1. The reducers in the slice here get access the value of the current state of `count` which is currently `0` through the automatic `state` parameter provided by redux toolkit and has the ability to change it depending on the logic inside the reducer.

We then pass in the built-in reducer property of the slice (`counterSlice.reducer`) as a value to the reducer key of the configureStore object and that sets up our store. The reducer property is automatically created by redux toolkit gives the store access to the values of the slice.The data slice actions are also exported from the store so they can be used to make changes to our data from anywhere in the application.

## MAKING OUR STORE GLOBALLY AVAILABLE 
We need to make the store globally available to all components and for that we go to the top of our components tree `index.js` in the root folder

We import the `store` from store/index.js and a special component called `Provider` from our helper package `react-redux` this component is used to wrap `App.js` it takes in a store props which we set to our imported store, this makes our store available for all our components.
```javascript
//  src/index.js

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store/index";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);
```

## SETTING UP OUR COMPONENTS TO MAKE USE OF REDUX
Create a file in the components folder called `Counter.js` it will contain our Counter component with empty functions which we will wire up to the slice actions so we can trigger the reducers to increase/decrease the count.

```javascript
const Counter = () => {
  const incrementHandler = () => {};

  const decrementHandler = () => {};

  return (
    <main>
      <h1>Redux Counter</h1>
       <h2>--Counter Value--</h2>
      <div>
        <button onClick={incrementHandler}>increase</button>
       
        <button onClick={decrementHandler}>decrease</button>
      </div>
    </main>
  );
};

export default Counter;
```

![before setting up useSelector](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g2pb1xhcpzag348v8d8p.PNG)

So in the `Counter.js` file we will be importing 3 things, the `counterActions` from store/index.js remember we exported the slice auto-generated actions earlier and two hooks from `react-redux` 1) `useSelector` for getting access to the state of your choice and 2) `useDispatch` to dispatch actions and trigger the reducer functions in your slice.

```javascript
import { useSelector, useDispatch } from "react-redux";
import { counterActions } from "../store";

const Counter = () => {
  //storing our dispach function into a value
  const dispatch = useDispatch();

  // 
  const count = useSelector((state) => state.count);

  const incrementHandler = () => {
    dispatch(counterActions.increment());
  };

  const decrementHandler = () => {
    dispatch(counterActions.decrement());
  };

  return (
    <main>
      <h1>Redux Counter</h1>
      <h1>{count}</h1>
      <div>
        <button onClick={incrementHandler}>increase</button>
        <button onClick={decrementHandler}>decrease</button>
      </div>
    </main>
  );
};

export default Counter;
```
Getting the state out of the store using useSelector hook is done by passing in a function that receives the state being managed in the store and picking the exact state we need which in this case is the `count` state and if we had multiple slices and therefore multiple reducers in our store reducer for example an authentication slice..

Example:

```javascript
//Single slice
const store = configureStore({
  reducer: counterSlice.reducer,
});

//Multiple slices
const store = configureStore({
 reducer: { counter: counterSlice.reducer, auth: authSlice.reducer }

});

```
you will then target the count state in the slice using this code 
instead >>> `const count = useSelector((state) => state.counter.count)` we have to go down one more level because the `count` and `auth` slices are now being stored in an object.

![after setting up useSelector](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nhktgo3uywwuvv9hf3ul.PNG)

Our decrease and increase buttons now work and the value of the count is displayed, We can take it a little further by passing in parameters to our slice actions/reducers.

```javascript
//  store/index.js

import { configureStore, createSlice } from "@reduxjs/toolkit";

const initialCounterState = { count: 0 };

const counterSlice = createSlice({
  name: "counter",
  initialState: initialCounterState,
  reducers: {
    increment: (state) => {
      state.count++;
    },
    decrement: (state) => {
      state.count--;
    },
    increaseByValue: (state, action) => {
      state.count = state.count + action.payload;
    },
  }
});

const store = configureStore({
  reducer: counterSlice.reducer,
});

export const counterActions = counterSlice.actions;

export default store;

```
I've added one more function to the reducers and this function is different from the others because it takes in another parameter called "action" which is an object containing a "payload" property, this property is what wil holds whatever argument we pass into the action in our Counter component.

```javascript
import { useSelector, useDispatch } from "react-redux";
import { counterActions } from "../store";

const Counter = () => {
  //storing our dispach function into a value
  const dispatch = useDispatch();

  // 
  const count = useSelector((state) => state.count);

  const incrementHandler = () => {
    dispatch(counterActions.increment());
  };

  const decrementHandler = () => {
    dispatch(counterActions.decrement());
  };

  const increaseByValueHandler = () => {
    dispatch(counterActions.increaseByValue(5));
      };

  return (
    <main>
      <h1>Redux Counter</h1>
      <h1>{count}</h1>
      <div>
  <button onClick={incrementHandler}>increase</button>
  <button onClick={decrementHandler}>decrease</button>
  <button onClick={increaseByValueHandler}>increase by 5</button>
      </div>
    </main>
  );
};

export default Counter;
```
## AND WE'RE DONE!
You can tweak the increaseByValue function to receive it's argument dynamically using useState or useRef to get the value of an input field but this is as far as I'll take it.

Of course redux-toolkit/react-redux are mainly used for more complicated state logic and across much more components but the purpose of this article was just to demonstrate how redux works and as you can see it's not that hard to set up.

See you next time. Mikey out✌🏾