Redux reducer — изменяет ли это состояние?

#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. Откуда вы это знаете? Согласно вопросу, это также может быть массив объектов.