Redux Setup
Redux Setup
State folder -> index.js
import { createSlice } from "@reduxjs/toolkit";
// Define the initial state of the application
const initialState = {
mode: "light", // Represents the current theme mode ("light" or "dark")
user: null, // Represents the currently logged-in user
token: null, // Represents the authentication token
posts: [], // Represents a list of posts
};
// Create a slice of the Redux store using the createSlice function from Redux Toolkit
export const authSlice = createSlice({
name: "auth", // Name of the slice
initialState, // Initial state of the slice
reducers: {
setMode: (state) => {
// Toggle the theme mode between "light" and "dark"
state.mode = state.mode === "light" ? "dark" : "light";
// Here, `state.mode` represents the previous theme mode (mode: "light"),
// and `state.mode === "light" ? "dark" : "light"` represents the new theme mode.
},
setLogin: (state, action) => {
// Set the logged-in user and authentication token
state.user = action.payload.user;
state.token = action.payload.token;
// Here, `action.payload` represents the data passed when dispatching this action.
// `action.payload.user` represents the user data,
// and `action.payload.token` represents the authentication token.
},
setLogout: (state) => {
// Clear the logged-in user and authentication token
state.user = null;
state.token = null;
},
setFriends: (state, action) => {
if (state.user) {
// Set the friends of the logged-in user
state.user.friends = action.payload.friends;
// Here, `action.payload.friends` represents the list of friends passed in the action payload.
} else {
console.error("user friends non-existent :(");
// If there is no logged-in user, an error message is logged to the console.
}
},
setPosts: (state, action) => {
// Set the list of posts
state.posts = action.payload.posts;
// Here, `action.payload.posts` represents the list of posts passed in the action payload.
},
setPost: (state, action) => {
// Update a specific post in the list of posts
const updatedPosts = state.posts.map((post) => {
if (post._id === action.payload.post._id) {
// If the post's _id matches the updated post's _id,
// replace it with the updated post in the new array
return action.payload.post;
}
return post;
});
state.posts = updatedPosts;
// Here, `action.payload.post` represents the updated post passed in the action payload.
},
},
});
// Extract the actions generated by the createSlice function
export const {
setMode,
setLogin,
setLogout,
setFriends,
setPosts,
setPost,
} = authSlice.actions;
export default authSlice.reducer;
We are using index.ts so we should modify this and using interfaces in TypeScript is a good practice for defining the types of your state and payload objects.
-
Added the
User
interface: Represents the structure of a user object with propertiesid
,name
, andfriends
. -
Added the
Post
interface: Represents the structure of a post object with properties_id
and any other relevant post properties. -
Added the
AuthState
interface: Represents the structure of the authentication state object, including propertiesmode
,user
,token
, andposts
. -
Updated the
initialState
declaration to use theAuthState
interface. -
Updated the payload types in the action creators:
setLogin
action now accepts an object with propertiesuser
of typeUser
andtoken
of typestring
.setFriends
action now accepts an object with afriends
property of typestring[]
.setPosts
action now accepts an object with aposts
property of typePost[]
.setPost
action now accepts an object with apost
property of typePost
.
-
Modified the
setFriends
reducer to use theproduce
function from theimmer
library to handle the immutability of the nesteduser
object. Theproduce
function ensures that the state is not modified directly and allows you to make
import { createSlice, Draft, PayloadAction } from "@reduxjs/toolkit";
import produce from "immer";
interface User {
id: string;
name: string;
friends: string[];
}
interface Post {
_id: string;
// Other post properties
}
interface AuthState {
mode: string;
user: User | null;
token: string | null;
posts: Post[];
}
const initialState: AuthState = {
mode: "light",
user: null,
token: null,
posts: [],
};
export const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
setMode: (state) => {
state.mode = state.mode === "light" ? "dark" : "light";
},
setLogin: (
state,
action: PayloadAction<{ user: User; token: string }>
) => {
state.user = action.payload.user;
state.token = action.payload.token;
},
setLogout: (state) => {
state.user = null;
state.token = null;
},
setFriends: (state, action: PayloadAction<{ friends: string[] }>) => {
state.user = produce(state.user, (draft: Draft<User | null>) => {
if (draft) {
draft.friends = action.payload.friends;
} else {
console.error("User object is null");
}
});
},
setPosts: (state, action: PayloadAction<{ posts: Post[] }>) => {
state.posts = action.payload.posts;
},
setPost: (state, action: PayloadAction<{ post: Post }>) => {
state.posts = state.posts.map((post) =>
post._id === action.payload.post._id ? action.payload.post : post
);
},
},
});
export const {
setMode,
setLogin,
setLogout,
setFriends,
setPosts,
setPost,
} = authSlice.actions;
export default authSlice.reducer;