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;
- 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;
- 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>
);
}
- Now that redux is setup, let's connect it to a component using useSelector and useDispatch hooks.
useSelector
: This hook allow you to extract data from redux store or selects the Redux state.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;
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);
//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>
);
}
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.
Top comments (0)