Mastering Redux Toolkit: A Step-by-Step Tutorial for New Developers.

In the world of building large applications, one of the biggest challenges, especially for teams of developers, is managing the state. While the Context API is useful, it has its limits, especially for applications with many features. To address this, several state management tools have been introduced, but Redux has emerged as a leading solution.

It is worth noting that Redux is not part of ReactJS, despite being frequently used together. While Redux solves many problems, it also introduces new challenges. Setting up a Redux store and writing reducers can be a cumbersome and error-prone process that involves a lot of boilerplate code and manual configuration. This is where the Redux Toolkit comes in - the creators of Redux recognized the need for a more opinionated approach to setting up Redux applications, resulting in the development of the Redux Toolkit, which can be thought of as Redux with batteries included.

The Redux Toolkit eliminates the need for additional libraries and configurations, speeding up the workflow significantly. With the Redux Toolkit, users can benefit from Redux without having to deal with manual setups.

This article will cover all the essential building blocks of the Redux Toolkit. Specifically, we will be developing a shopping cart application that allows users to add and remove items, displaying the total price of the items in their cart. We will explore many of the features of the Redux Toolkit, including Store, Slice, Reducers, and Action Creators.

What we will cover

Setting up the Project
Installing Redux Toolkit
Creating the Redux Store
Setup Provider
Creating the Cart Slice
Creating the UI Components
Rendering the App
Running the App
Conclusion

Step 1: Setting up the Project

We will start by creating a new React project using Create React App. Open up your terminal and run the following command:

npx create-react-app shopping-cart

Once the project is created, navigate to the project directory:

cd shopping-cart

Step 2: Installing Redux Toolkit

Next, we need to install Redux Toolkit. Run the following command in your terminal:

npm install @reduxjs/toolkit react-redux

This will install the latest version of Redux Toolkit and add it to our project dependencies. Redux can be used for any frontend framework and is not specific to react, so in order to connect our Redux with react this is where the react-redux comes in.

Just a side note: When we install @reduxjs/toolkit we actually installed a few libraries which are:

- redux (core library, state management)
- immer (which allow us to mutate the state)
- redux-thunk (which will handles the async actions)
- reselect (which will simplifies the reducer functions)

All these will make sense if you have worked with Redux, but if you haven't worked with Redux before don't worry I will explain all of those as we go.

As an extra, we also get:

- redux devtools
- combine reducers

Step 3: Creating the Redux Store

You are going to think of the store as the entire state of your application.
Create a new file called store.js in the src directory and add the following code:

import { configureStore } from '@reduxjs/toolkit'; 
import cartReducer from './features/cart/cartSlice';

export default configureStore({ 
    reducer: { 
        cart: cartReducer, 
    }, 
});

This code imports the configureStore function from Redux Toolkit and our cartReducer from a file that we will create in the next step. It then exports the configured Redux store.

Step 4: Setup Provider

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

// import store and provider
import { store } from './store';
import { Provider } from 'react-redux';

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

Next, we import the store and Provider and then wrap the entire application with the Provider and pass the store as props.

Step 5: Creating the Cart Slice

I want you to think of slice as the features of your application for example increasing and decreasing the number of items in the cart or triggering a modal. The bigger the application the more features we are going to have. And in the Redux toolkit land, it is called slice.

To setup a slice, a common convention is to create a features folder, Create a new directory called features in the src directory, and inside it, create a new directory called cart. Inside the cart directory, create a new file called cartSlice.js and add the following code:

import { createSlice } from '@reduxjs/toolkit';

export const cartSlice = createSlice({
  name: 'cart',
  initialState: [],
  reducers: {
    addToCart: (state, action) => {
      const index = state.findIndex(item => item.id === action.payload.id);
      if (index !== -1) {
        state[index].quantity += 1;
      } else {
        state.push({ ...action.payload, quantity: 1 });
      }
    },
    removeFromCart: (state, action) => {
      const index = state.findIndex(item => item.id === action.payload);
      if (index !== -1) {
        state.splice(index, 1);
      }
    },
    incrementQuantity: (state, action) => {
      const index = state.findIndex(item => item.id === action.payload);
      if (index !== -1) {
        state[index].quantity += 1;
      }
    },
    decrementQuantity: (state, action) => {
      const index = state.findIndex(item => item.id === action.payload);
      if (index !== -1) {
        state[index].quantity -= 1;
        if (state[index].quantity === 0) {
          state.splice(index, 1);
        }
      }
    },
  },
});

export const { addToCart, removeFromCart, incrementQuantity, decrementQuantity } = cartSlice.actions;

export default cartSlice.reducer;

export const selectCart = state => state.cart;

export const selectCartTotal = state => state.cart.reduce((total, item))

Let's understand what's happening in the code above.
The cartSlice.js contains the initial state of an empty array and several reducer functions for adding, removing, and updating items in the cart.

The addToCart reducer function checks if the item being added already exists in the cart by checking if its id matches any existing items in the cart. If it does, it increments the quantity of that item. If not, it adds the new item to the cart with a quantity of 1.

The removeFromCart reducer function removes an item from the cart by finding the index of the item with the id that matches the payload of the action being dispatched. If the item is found, it is removed from the cart using the splice method.

The incrementQuantity reducer function increments the quantity of an item in the cart by finding the index of the item with the id that matches the payload of the action being dispatched and incrementing its quantity.

The decrementQuantity reducer function decrements the quantity of an item in the cart by finding the index of the item with the id that matches the payload of the action being dispatched and decrementing its quantity. If the quantity of the item becomes 0, the item is removed from the cart using the splice method.

The cartSlice.actions object exports the four reducer functions defined in the reducers property of the createSlice function.

The selectCart and selectCartTotal functions are selectors that are used to access the cart slice of the Redux store and compute the total price of all items in the cart.

Finally, the export default statement exports the cartSlice.reducer function, which is used to create the Redux store for the shopping cart.

Overall, this code defines the structure and behavior of the shopping cart slice.

Step 5: Creating the UI Components

Now that we have our Redux store and cartSlice set up, we can start building the UI components for our shopping cart application. In the src directory, create a new directory called components. Inside the components directory, create a new file called Cart.js and add the following code:

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import {
  selectCart,
  selectCartTotal,
  addToCart,
  removeFromCart,
  incrementQuantity,
  decrementQuantity,
} from '../features/cart/cartSlice';

const Cart = () => {
  const cart = useSelector(selectCart);
  const total = useSelector(selectCartTotal);
  const dispatch = useDispatch();

  const handleAddToCart = item => {
    dispatch(addToCart(item));
  };

  const handleRemoveFromCart = id => {
    dispatch(removeFromCart(id));
  };

  const handleIncrementQuantity = id => {
    dispatch(incrementQuantity(id));
  };

  const handleDecrementQuantity = id => {
    dispatch(decrementQuantity(id));
  };

  return (
    <div>
      <h2>Shopping Cart</h2>
      {cart.length === 0 ? (
        <p>Your cart is empty.</p>
      ) : (
        <>
          <ul>
            {cart.map(item => (
              <li key={item.id}>
                <div>
                  <span>{item.name}</span>
                  <button onClick={() => handleRemoveFromCart(item.id)}>-</button>
                  <span>{item.quantity}</span>
                  <button onClick={() => handleIncrementQuantity(item.id)}>+</button>
                  <span>${item.price * item.quantity}</span>
                </div>
              </li>
            ))}
          </ul>
          <p>Total: ${total}</p>
        </>
      )}

      <button onClick={() => handleAddToCart({ id: 1, name: 'Item 1', price: 10 })}>Add Item 1 to Cart</button>
      <button onClick={() => handleAddToCart({ id: 2, name: 'Item 2', price: 20 })}>Add Item 2 to Cart</button>
    </div>
  );
};

export default Cart;

This code defines a Cart the component that uses the useSelector and useDispatch hooks from React Redux to access the cart state and dispatch actions to the Redux store. It also defines several event handlers for adding and removing items from the cart and updating item quantities.

Step 6: Rendering the App

Finally, we need to render our Cart component in our App component. Open up the App.js file in the src directory and replace the existing code with the following:

import React from 'react';
import './App.css';
import Cart from './components/Cart';

function App() {
  return (
    <div className="App">
      <Cart />
    </div>
  );
}

export default App;

This code simply renders our Cart component in the App component.

Step 7: Running the App

With our project setup and our code written, we can now run our shopping cart application. Open up your terminal and run the following command:

npm start

This will start the development server and open up the shopping cart application in your browser.

Conclusion

In this article, we learned how to use Redux Toolkit to simplify the process of creating a Redux store and how to build a shopping cart application using React and Redux Toolkit. We created a cartSlice that contained the reducer, actions, and selectors