#reactjs #redux #react-redux
#reactjs #redux #react-redux
Вопрос:
Я наткнулся на следующий redux reducer, и хотя он работает нормально, я считаю, что это неправильно:
export default (state = initState, action) => {
switch (action.type) {
case RESET_SCREEN:
return Object.assign({}, state, initState);
case MODIFY_ITEM:
let itemId = state.item.id;
state.items[itemId].item = action.item;
return Object.assign({}, state, {items: state.items});
}
}
Правильно ли, что RESET_SCREEN хорош, потому что он не изменяет состояние, однако часть MODIFY_ITEM плоха, потому что она изменяет? В каких случаях это повредит? (потому что приложение в настоящее время ведет себя так, как ожидалось)
Какова альтернатива MODIFY_ITEM?
Комментарии:
1. пожалуйста, покажите структуру вашего
initState
Ответ №1:
Правильно ли, что RESET_SCREEN хорош, потому что он не изменяет состояние
Да, это правильно.
однако часть MODIFY_ITEM плоха, потому что она изменяет
Нет, MODIFY_ITEM
не изменяет состояние:
Эта строка: state.items[itemId].item = action.item;
изменяет объект (не состояние), но redux
не заботится о локальной мутации объекта — он бы даже не знал.
Пока вы возвращаете новую ссылку — новую копию объекта, redux
считает это допустимым новым состоянием.
Итак, согласно redux,
это изменение состояния:
case MODIFY_ITEM:
let itemId = state.item.id;
state.items[itemId].item = action.item;
return state; // <-- because you are returning the same reference. BAD
Это НЕ изменение состояния:
case MODIFY_ITEM:
let itemId = state.item.id;
state.items[itemId].item = action.item;
return Object.assign({}, state, {items: state.items}); // <- A new Object. GOOD
Возможно, вы захотите прочитать о мелкой проверке и изменении состояния здесь.
Ответ №2:
Вы изменяете предыдущее состояние в этой строке
state.items[itemId].item = action.item;
Ответ №3:
Вы можете использовать immer npm.
Это крошечный пакет, который позволяет вам работать с неизменяемым состоянием более удобным способом. Он основан на механизме копирования при записи.
Ответ №4:
Чтобы сохранить неизменность состояния, вы могли бы написать MODIFY_ITEM
обработчик действий следующим образом:
case MODIFY_ITEM:
let itemId = state.item.id;
return {...state, items: state.items.map((item, index) => {
return index === itemId ? action.item : item
})}
Комментарии:
1.
state.items
является объектом.2. Откуда вы это знаете? Согласно вопросу, это также может быть массив объектов.