Open In App

Why is immutability important in Redux?

Redux is a state container for JavaScript applications. It's specially designed for building complex and scalable web applications. Redux is commonly used with frameworks like React and Angular for managing application state.

In this article, we will learn more about Redux and immutability in Redux.

Why Redux?

What is Immutability?

Immutability in Redux ensures that state objects remain unchanged once they are created. Instead of modifying state directly, Redux helps updating state by creating new copies with the desired changes. This principle ensures predictable state transitions and provides efficient change detection, debugging, and performance optimization. By using immutability, Redux increases functional programming, prevents unintended side effects, and enhances the maintainability and scalability of applications.

Why Immutability is important in Redux?

Steps to Create the Application:

To create this react application we will use vite as faster developing experience build tool.

Step 1: Create the application using the following command

npm create vite@latest .

Step 2: Install npm using the following command.

npm install

Step 3: Install the required dependencies

npm install react-router react-router-dom react-redux tailwindcss redux-persist react-persist

Project Structure:
Screenshot-2024-04-16-173137Package.json

"dependencies": {
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.0.0",
"nodemon": "^3.0.1"
}

Example of Immutability in Redux with React.js application:

//main.jsx

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { persistor, store } from "./redux/store.js";
import { PersistGate } from "redux-persist/integration/react";


ReactDOM.createRoot(document.getElementById("root")).render(
    <Provider store={store}>
        <PersistGate persistor={persistor} loading={null}>
            <BrowserRouter>
                {" "}
                <App />
            </BrowserRouter>
        </PersistGate>

    </Provider>
);
//App.jsx

import { useState } from 'react'
import { Routes, Route } from 'react-router-dom'
import './App.css'
import Home from './pages/Home'

function App() {

    return (

        <>
            <Navbar />
            <Routes>

                <Route path="/" element={<Home />} />

            </Routes>
        </>
    )
}

export default App
//Home.jsx

import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { decerement, increment } from "../redux/user/counterSlice";

const Home = () => {
    const dispatch = useDispatch();

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

    return (
        <>
            <div>
                <div
                    className="con-main"
                    style={{ textAlign: "center", marginTop: "25%" }}
                >
                    <h1>
                        Counter = <strong>{count}</strong>
                    </h1>
                    <div
                        className="con1"
                        style={{ display: "flex", justifyContent: "space-evenly" }}
                    >
                        <button
                            style={{
                                border: "1px solid black",
                                borderRadius: "2px 2px 3px 2px",
                                padding: "0.5rem 1rem",
                                backgroundColor: "green",
                            }}
                            onClick={() => dispatch(increment())}
                        >
                            Increment
                        </button>
                        <button
                            style={{
                                border: "1px solid black",
                                borderRadius: "2px 2px 3px 2px",
                                padding: "0.5rem 1rem",
                                backgroundColor: "red",
                            }}
                            onClick={() => dispatch(decerement())}
                        >
                            Decrement
                        </button>
                    </div>
                </div>
            </div>
        </>
    );
};

export default Home;
//store.js

import {
    combineReducers,
    configureStore,
    getDefaultMiddleware,
} from "@reduxjs/toolkit";
import userReducer from "./user/userSlice.js";
import { persistReducer, persistStore } from "redux-persist";
import storage from "redux-persist/lib/storage";
import counterReducer from "./user/counterSlice.js";

const rootReducer = combineReducers({
    user: userReducer,
    counter: counterReducer,
});

const persistConfig = {
    key: "root",
    version: 1,
    storage,
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = configureStore({
    reducer: persistedReducer,
    middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware({
            serializableCheck: false,
        }),
});

export const persistor = persistStore(store);
//counterSlice.js

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

const initialState = {
    count: 0,
}

const counterSlice = createSlice({
    name: 'counter',
    initialState,
    reducers: {
        increment: (state) => {
            state.count += 1;
        },
        decerement: (state) => {
            state.count -= 1;
        }
    }
})

export const { increment, decerement } = counterSlice.actions

export default counterSlice.reducer


Immutability Demonstrated:
Now for the above in the increment and decrement state we directly change the count value by +1 and -1 that violates immutability rules. So instead of directly modifying the count value we can return a object. Here in this example we just updated the new state object with count value.

//counterSlice.js

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

const initialState = {
    count: 0,
}

const counterSlice = createSlice({
    name: 'counter',
    initialState,
    reducers: {
        increment(state) {
            return {
                ...state,
                count: state.count + 1
            };
        },
        decrement(state) {
            return {
                ...state,
                count: state.count - 1
            };
        }
    }
})

export const { increment, decerement } = counterSlice.actions

export default counterSlice.reducer

To start the application run the following command

npm run dev

Output:

Redux Immutability example

Redux immutability example

Article Tags :