I have this project, and I have api and through this api, the users in the Database are returned, but in the response, data is returned in addition to two variables, the first “isActive” and the second “isVerified”, and through these two values I can control the display, which means I can control the The data values that will be displayed on the interface,
If the value of the previous two variables is False, it means that the user has been rejected. Therefore, I save the rejected user in the "UsersRequests" array, and then I display the values in the "UsersRequests" array on the interface called "Users Requests"
And if the value of the previous two variables is true, then this means that the user has been accepted and has become a user of the site, so I save the user in the array “Users”, Then I display the values in the "Users" array on the interface called "Users".
And based on the previous cases, I filtered the values coming from the backend
But I got this error:
[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.
How can I solve the problem?
import {
createSlice,
createAsyncThunk,
createEntityAdapter,
} from "@reduxjs/toolkit";
import axios from "axios";
export const getUsersRequests = createAsyncThunk(
"usersRequests/getUsersRequests",
async () => {
const response = await axios
.get("/users/for-admin")
.catch((err) => console.log(err));
const usersRequestsData = response.data.data;
console.log("data inside Slice:", usersRequestsData);
return usersRequestsData;
}
);
// This is one of the keys 'slice name' which is 'usersRequests'
const contactsSlice = createSlice({
name: "usersRequests",
initialState: {
data: [],
usersRequests: [],
status: null,
approve: null,
acceptedUsers: [],
},
reducers: {},
extraReducers: {
[getUsersRequests.pending]: (state) => {
state.status = "loading";
},
[getUsersRequests.fulfilled]: (state, { payload }) => {
state.status = "success";
state.data = payload;
console.log("inside coooontact Slice: ", state.data);
return state.data.filter((user) => {
if (user.isActive == false && user.isVerified == false) {
state.usersRequests = user;
} else {
state.users = user;
}
});
},
[getUsersRequests.rejected]: (state) => {
state.status = "failed";
},
});
export default contactsSlice.reducer;
CodePudding user response:
Two trouble for me :
One in the extraReducer you need to use builder like that :
extraReducers:(builder) => {
builder.addCase(-typeAction-, state => {
//doSomething...
// state.value = newValue;
});
}
See : https://redux-toolkit.js.org/api/createslice
Second trouble (less) :
return state.data.filter((user) => {
if (user.isActive == false && user.isVerified == false) {
state.usersRequests = user;
} else {
state.users = user;
}
});
Try to change for :
state.data.forEach((user) => {
...
D'après MozillaDev : La méthode forEach() permet d'exécuter une fonction donnée sur chaque élément du tableau. La méthode filter() crée et retourne un nouveau tableau contenant tous les éléments du tableau d'origine qui remplissent une condition déterminée par la fonction callback.
So you return a value on a Reducer with redux-toolkit, Immer don't like that.
Say me if it's good for you.
//edit
extraReducers: (builder) => {
builder
.addCase(getUsersRequests.pending: (state) => {
state.status = "loading";
}),
.addCase(getUsersRequests.fulfilled: (state, { payload }) => {
state.status = "success";
state.data = payload;
console.log("inside coooontact Slice: ", state.data);
state.data.forEach((user) => {
if (user.isActive == false && user.isVerified == false) {
state.usersRequests = user;
} else {
state.users = user;
}
});
}),
.addCase(getUsersRequests.rejected: (state) => {
state.status = "failed";
}),
CodePudding user response:
In a reducer created with createSlice
, the state
parameter is an Immer draft. Your reducer function must either modify the draft or return a new object, but not both. As you've implemented the reducer, the assignment of the status
and data
properties modify the draft, but then the value produced by state.data.filter
is returned. This causes the error message you're seeing.
Instead, iterate through state.data
and modify the two user properties, but do not explicitly return anything from the function. It might look something like this (extracted to a named function for demonstration):
function getUserRequestsFulfilled(state, { payload }) {
state.status = "success";
state.data = payload;
state.data.forEach((user) => {
if (user.isActive == false && user.isVerified == false) {
state.usersRequests.push(user);
} else {
state.users.push(user);
}
});
}