State Management in React Using Redux Toolkit (RTK)

Dushyanth N Gowda
Version 1
Published in
6 min readMar 28, 2023

State management, Redux, and Redux Toolkit

In React, the state is a fundamental feature that enables components to manage and store their internal data, representing the current state of the component. By updating the state, components can react to external or internal events and change their behavior and rendering accordingly.

One of the significant benefits of using state is that it allows components to become more dynamic and interactive by providing a way to manage and update their data dynamically. Components can pass their state data as props to other components, allowing them to interact and exchange data seamlessly. Overall, the state is a critical tool for building dynamic, reactive, and interactive user interfaces in React.

Imagine that we have multiple components, where we need to pass information from Component 1 to Component 10 via an intermediate component, Component 2, Component 3, and so on. In such cases, the data has to be passed from Component 1 to multiple intermediate components to reach the final destination. This practice of passing data through multiple levels of components is called “prop drilling”.

Prop drilling can lead to complications, especially when we have to pass the same data across many levels of components. In scenarios where we need to share state between sibling components across many levels, managing state effectively becomes crucial. This is where state management comes into the picture. By lifting the state to a common ancestor, we can avoid prop drilling and provide the necessary state to all the child components that require it.

So what is state management in React?

In React, state management is the process of managing and sharing the state data of an application in a centralized and efficient way. Instead of storing and managing state data at the component level, state management allows us to maintain a central store of the state that can be accessed by any component in the application.

This central store is typically managed by a state management tool, such as Redux, MobX, or React Context API. These tools provide a way to define, update, and access the application state in a standardized and scalable way, without the need to pass data from one component to another.

Redux and Redux Toolkit

Redux is a state management library that is commonly used in React applications. It provides a way to manage the application’s state. The core idea of Redux is to have a single source of truth for the application’s state, which is called the store. Components can dispatch actions to the store, which trigger reducers to update the store’s state. By using Redux, we can avoid the complexity of prop drilling and manage the application’s state in a scalable, predictable, and maintainable way.

https://redux.js.org/tutorials/fundamentals/part-2-concepts-data-flow
Source: https://redux.js.org/tutorials/fundamentals/part-2-concepts-data-flow

Redux toolkit does the same, but this comes with much less boilerplate code to set up and is easy to understand. It reduces boilerplate code by providing a set of pre-configured tools that simplify common Redux tasks. For example, it provides a createSlice function that generates action creators and reducers automatically based on a specified initial state and a set of “slice” reducers. It also includes a middleware stack that handles common tasks like logging, async requests, and error handling.

Enough with the theory, let’s jump into coding.

We can use https://codesandbox.io/ to code on the go or if you already have your local setup, then that works too. Add these two extra dependencies to your project.

npm install react-redux @reduxjs/toolkit

We’ll be creating a simple application to increment or decrement a number using different components. First, let’s create a state for the application. I’ve created a new directory called the store and added a new file called slice-store.js

  • We’ll be using createSlice from the reduxjs toolkit.
  • createSlice accepts the initial state, slice name, and reducers.
import { createSlice } from "@reduxjs/toolkit";

let initialState = { count: 0 };

export const slice = createSlice({
name: "counter",
initialState,
reducers: {
increment(state) {
state.count = state.count + 1;
},
decrement(state) {
state.count = state.count - 1;
},
random(state, action) {
state.count = action.payload;
}
}
});

export const sliceReducers = slice.actions;

Now we need to create a store for all our components to access the state.

  • Adding a new file called configure-store.js in the same directory, here we are using configureStore from the reduxjs toolkit. It accepts reducer functions as arguments and automatically sets up the Redux DevTools Extension for easy debugging.
import { configureStore } from "@reduxjs/toolkit";
import { slice } from "./slice-store";

export const store = configureStore({
reducer: {
counter: slice.reducer
}
});

Now that the store is successfully created, we need components to access and modify the state. This can be achieved by using the Provider from the react-redux package.


import { createRoot } from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import { store } from "./store/configure-store";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
<Provider store={store}>
<App />
</Provider>
);

Now that the store is created, it’s time for us to use this store to display and dispatch an action to modify the state of the action. In index.js pass the new store to the Provider component. Components under the App component can access and manage the store.

I’ll add four more components to my application, one to display the count value and the other three components to dispatch events to modify the state accordingly.

In the code example, four components interact with the Redux store. The Display component displays the current count from the store and three other components have different buttons to increment, decrement, and generate a random count value. When the buttons are clicked, they dispatch actions to the store, which triggers the sliceReducer to update the count and a new state value will be rendered in the Display component.

Wrap these newly created components in the App.js file for them to access the store.

import { Display } from "./components/Display";
import { Increment } from "./components/Increment";
import { Decrement } from "./components/Decrement";
import { Random } from "./components/Random";

export default function App() {
return (
<>
<div className="appContainer">
<Display />
<Increment />
<Decrement />
<Random />
</div>
</>
);
}

All done! Now you should be able to increment or decrement or generate a random count number from different components without having to worry about passing the state across components. You can use the following extension https://github.com/reduxjs/redux-devtools to see the state change in your browser.

App link: https://p03ets.csb.app/

Source code: https://codesandbox.io/s/p03ets

Practices to follow:

  • If you have a very large application then it’s important to structure your store in a way that makes it easy to manage and scale. This can include breaking up your store into smaller sub-stores that are more focused on specific parts of the application.
  • We need to use middleware to handle tasks like logging, async requests, and error handling. Redux toolkit gives us the option to add thunk middleware in configureStore directly, if you are interested then you can follow this link to read more about it.

Additional read:

Managing state: https://react.dev/learn/managing-state

Redux: https://redux.js.org/

Redux Toolkit: https://redux-toolkit.js.org/

About the author

Dushynath Gowda is a React Developer at Version 1.

--

--