DEV Community

Cover image for Minimal way to setup Redux toolkit
Sanjokale
Sanjokale

Posted on

Minimal way to setup Redux toolkit

Redux is a predictable state container for javascript applications. It is popular in react applications, but it can be used with other frameworks as well.

Key Reasons For Using Redux:

  • Centralized State Management:Redux provides a single, centralized store to manage the applicaiton's state. This makes it easier to track and manage state changes, especially in complex applcations with many components.

  • Facilitated Complex State Logic:Redux provides a structured way to manage it, preventing issues like "prop drilling"

  • State Persistence:Libraries like Redux persist, allow for saving application states, through page refreshes, or even applicaiton restarts.

Follow these steps to integrate Redux Toolkit into your NextJs appication:-

Installation
npm install @reduxjs/toolkit react-redux

Configuring Redux Toolkit in Next.js (app router)

  • Create a redux folder to store the files related to redux setup files in /src directory. Inside the src/redux directory create a store.js file.

  • Configure the Redux store in store.js

// store.js
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './userSlice'; // Import your userSlice

const store = configureStore({
  reducer: {
    user: userReducer, // Add your user reducer to the store
    // ... other reducers if you have them
  },
});

export default store;
Enter fullscreen mode Exit fullscreen mode
  • Create folder in your src/redux directory and after that create a slices. Redux slices manage a section of the state and contain actions and raducers.
//redux/slices/userSlice.js

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

const initialState = {
  userDetails: null, // Initially, no user details
};

const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    setUserDetails: (state, action) => {
      state.userDetails = action.payload;
    },
    clearUserDetails: (state) => {
      state.userDetails = null;
    },
  },
});

export const { setUserDetails, clearUserDetails } = userSlice.actions;
export default userSlice.reducer;

Enter fullscreen mode Exit fullscreen mode
  • To make Redux available across your Next.js app, wrap the Redux Provider.
//RootLayout layout.js
'use client'; // Required for client-side hooks

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

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <Provider store={store}>
          {children}
        </Provider>
      </body>
    </html>
  );
}

Enter fullscreen mode Exit fullscreen mode
  • Now that redux is setup, let's connect it to a component using useSelector and useDispatch hooks.
  1. useSelector: This hook allow you to extract data from redux store or selects the Redux state.

  2. useDispatch: This hook returns a reference to the dispatch funciton from the Redux store. You use the dispatch function to send the action to store which trigger state update.

//Example componenet (e.g., userProfile.js)
'use client'
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { setUserDetails, clearUserDetails } from './userSlice';

function UserProfile() {
  const userDetails = useSelector((state) => state.user.userDetails);
  const dispatch = useDispatch();

//here data is come from the api call of getUser
  const mockUserDetails = {
    userId: 'user123',
    username: 'john.doe',
    firstName: 'John',
    lastName: 'Doe',
    email: 'john.doe@example.com',
    phoneNumber: '123-456-7890',
    address: {
      street: '123 Main St',
      city: 'Anytown',
      state: 'CA',
      zip: '91234',
      country: 'USA',
    },
    dateOfBirth: '1990-05-15',
    registrationDate: '2023-10-26T10:00:00Z',
    lastLogin: '2023-10-27T14:30:00Z',
    isActive: true,
    profilePicture: 'https://example.com/images/user123.jpg',
  };

  const handleSetUserDetails = () => {
    dispatch(setUserDetails(mockUserDetails));
  };

  const handleClearUserDetails = () => {
    dispatch(clearUserDetails());
  };

  if (!userDetails) {
    return (
      <div>
        <p>No user details available.</p>
        <button onClick={handleSetUserDetails}>Set User Details</button>
      </div>
    );
  }

  return (
    <div>
      <h2>User Profile</h2>
      <p>Username: {userDetails.username}</p>
      <p>Email: {userDetails.email}</p>
      {/* ... other user details */}
      <button onClick={handleClearUserDetails}>Clear User Details</button>
    </div>
  );
}

export default UserProfile;

Enter fullscreen mode Exit fullscreen mode

Implementing redux middleware like redux logger and redux persist

  • redux-logger: Logs all Redux actions and state changes to the console, making it easy to debug your Redux store

  • redux-persist: Saves the Redux store's state to localStorage (or another storage engine). When the app is reloaded, redux-perdidt loads the saved state back into the store

  • PersistGate: Ensure that the app doesn't render until the persisted state is loaded, preventing potential issues with rendeing componets that rely on the persisted data.

Installation
npm install redux-logger redux-persist

key changes on these files I mentioned above

//store.js
'use client'
import { combineReducers, configureStore } from "@reduxjs/toolkit"
import userReducer from "../slices/userSlice"
import logger from "redux-logger"
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
const persistConfig = {
  key: "root",  //key for local storage
  storage,
};

const rootReducer = combineReducers({ 
  user: userReducer,
})
const persistedReducer = persistReducer(persistConfig,rootReducer);


export const store = configureStore({
  reducer: persistedReducer,
  middleware: ()=> [logger]
})

export const persistor = persistStore(store);

Enter fullscreen mode Exit fullscreen mode
//layout.js
'use client'; // Required for client-side hooks
import { persistor, store } from "@/redux/store"
import { PersistGate } from "redux-persist/integration/react"


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

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <Provider store={store}>
          <PersistGate loading={null} 
           persistor={persistor}>
          {children}
          </PersistGate>
        </Provider>
      </body>
    </html>
  );
}
Enter fullscreen mode Exit fullscreen mode

This setup will persist the user details across browser reloads, and you will able to see the redux action and state changes in the console.

Image description

Top comments (0)