Вопрос или проблема
**У меня возникли проблемы с обновлением состояния в React с использованием Redux. Мое состояние – это список объектов, и по какой-то причине оно не обновляется правильно, когда я пытаюсь его изменить. Вместо обновленного списка я продолжаю получать прокси-массив, когда печатаю состояние в консоли. Я не уверен, правильно ли я обрабатываю неизменяемость или что-то упускаю в своем редьюсере. Мог бы кто-нибудь помочь мне разобраться, что идёт не так, или дать рекомендации о том, как правильно обновить состояние, которое является массивом объектов?
**
Это мой TodoSlice
import { createSlice, current, PayloadAction } from "@reduxjs/toolkit";
export interface Todo {
id: string;
task: string;
completed: boolean;
}
export const TOGGLE_COMPLETE = "TOGGLE";
export const UPDATE = "UPDATE";
const initialState: Array<Todo> = [
{
id: "1123123",
task: "Динамические отчеты и панели мониторинга",
completed: false
},
{
id: "2352352",
task: "Шаблоны для всех",
completed: true
},
{
id: "46264624",
task: "Процесс разработки",
completed: true
},
{
id: "68576",
task: "Безграничная бизнес-автоматизация",
completed: false
}
];
const todoSlice = createSlice({
name: "todoSlice",
initialState,
reducers: {
updateTodo: (state, action: PayloadAction<Todo>) => {
state = [...current(state).map(todo => todo.id === action.payload.id ? { ...action.payload } : todo)];
console.log(state);
},
updateTodoTask: (state, action: PayloadAction<Todo>) => {
state = state.map(todo => todo.id === action.payload.id ? { ...action.payload } : todo);
},
addTodo: (state, action: PayloadAction<{task: string, completed: boolean}>) => {
const id = Math.max(...state.map(todo => parseInt(todo.id))) + 1;
const todo: Todo = {id : ""+id, task: action.payload.task, completed: action.payload.completed};
state.push(todo);
},
deleteTodo: (state, action: PayloadAction<Todo>) => {
console.log(action.payload)
state = state.filter(todo => todo.id === action.payload.id ? { ...action.payload } : todo);
}
}
});
export const {updateTodo, addTodo, deleteTodo} = todoSlice.actions;
export default todoSlice.reducer;
store
import { configureStore } from "@reduxjs/toolkit";
import modalSlice from "./state/modalSlice";
import todoSlice from "./state/todoSlice";
export const store = configureStore({
reducer: {
modal: modalSlice,
todo: todoSlice
},
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
serializableCheck: false
}),
});
export type RootType = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
Это функции, которые вызывают Redux dispatch
const dispatch = useDispatch();
const list = useSelector((state: RootType) => state.todo);
const [editableTodo, setEditableTodo] = useState(temp);
const [isEditable, setIsEditAble] = useState(false);
const updateTodoItem = () => {
if(editableTodo != null && editableTodo.id != null && editableTodo.id != "" && editableTodo.task != null && editableTodo.task != "" && editableTodo.completed != null)
dispatch(updateTodo(editableTodo));
toggleEdit();
}
const deleteTodoItem = () => {
if(editableTodo != null && editableTodo?.id != null) dispatch(deleteTodo(editableTodo));
toggleEdit();
}
const toggleEdit = (todo?: Todo, save: boolean = false) => {
if(!editableTodo && todo != null) {
setEditableTodo(todo);
setIsEditAble(true);
}
else{
if(save) updateTodoItem();
setIsEditAble(false);
setEditableTodo(null);
}
}
Я пытался обновить всё состояние, а также найдя точный элемент. Я использовал current(state), поскольку печать состояния выводит ProxyArray длиной 1
.
Ответ или решение
Вам предстоит разобраться с проблемой обновления состояния в вашем приложении React с использованием Redux. Давайте подробно проанализируем предоставленный код и выясним, что могло пойти не так при обновлении списка задач.
Причины, по которым Redux
не обновляет список правильно:
-
Неверное использование состояния в редьюсере:
В некоторых ваших редьюсерах вы пытаетесь переназначить переменнуюstate
, вместо того чтобы изменять само состояние. ВRedux Toolkit
, который основан на Immer, вы можете изменятьstate
напрямую, и это будет работать корректно. -
Отсутствие возвращаемого значения в редьюсерах:
Некоторые редьюсеры, такие какupdateTodo
иdeleteTodo
, не имеют корректной логики изменения состояния. Вам не нужно присваивать новое значениеstate
. Вместо этого просто модифицируйтеstate
напрямую. -
Использование
ProxyArray
:
Это происходит из-за того, что состояние, возвращаемое изuseSelector
, относится к типуProxy
, и если вы пытаетесь его распечатать без преобразования, это может выглядеть не так, как вы ожидаете. Это нормально для структур данных, использующих Immer, и обычно не должно вызывать проблем.
Рекомендации по обновлению вашего редьюсера
Давайте очистим ваши редьюсеры, чтобы они правильно изменяли состояние:
const todoSlice = createSlice({
name: "todoSlice",
initialState,
reducers: {
updateTodo: (state, action: PayloadAction<Todo>) => {
const index = state.findIndex(todo => todo.id === action.payload.id);
if (index !== -1) {
state[index] = { ...state[index], ...action.payload }; // Обновите только нужные поля
}
console.log(state);
},
updateTodoTask: (state, action: PayloadAction<Todo>) => {
const index = state.findIndex(todo => todo.id === action.payload.id);
if (index !== -1) {
state[index] = { ...state[index], ...action.payload }; // Будьте внимательны к тому, что обновляете
}
},
addTodo: (state, action: PayloadAction<{ task: string, completed: boolean }>) => {
const id = String(Math.max(...state.map(todo => parseInt(todo.id))) + 1);
const todo: Todo = { id, task: action.payload.task, completed: action.payload.completed };
state.push(todo);
},
deleteTodo: (state, action: PayloadAction<Todo>) => {
const index = state.findIndex(todo => todo.id === action.payload.id);
if (index !== -1) {
state.splice(index, 1); // Удалить задачу из состояния
}
}
}
});
Правильный вызов dispatch
Также убедитесь, что ваши функции вызова dispatch
производятся корректно, как вы уже делали это. Проверьте наличие корректных значений в editableTodo
, прежде чем вызывать dispatch
.
Советы по отладке
- Отладка состояния: Используйте Redux DevTools для отслеживания состояния вашего хранилища и действий, которые его изменяют.
- Печать состояния: Вставьте дополнительные console.log в редьюсеры для контроля изменений состояния во время выполнения.
- Тестирование отдельных редьюсеров: Создайте тесты для каждого из ваших редьюсеров, чтобы убедиться, что они работают правильно и ожидаемым образом.
Заключение
Используя эти рекомендации, вы сможете настроить правильное обновление состояния в вашем приложении с помощью Redux. Внимательно следите за тем, как вы изменяете состояние, и используйте средства отладки, чтобы убедиться в его корректной работе. Redux Toolkit значительно упрощает работу с состоянием, но требует аккуратного обращения с изменениями данных.