Redux: Вопрос: Мутация внутреннего объекта в состоянии в редюсере

Созданный на 15 апр. 2016  ·  3Комментарии  ·  Источник: reduxjs/redux

Является ли это действительным редукторным редуктором?

function reducer(state={ byId: {}, ids: [] }, action) {
  switch (action.type) {
    case 'ADD':
      state = { ...state }
      state.byId[action.id] = action.value
      state.ids.push(action.id)
      return state

    default:
      return state
  }
}

Сначала поверхностно клонируется все состояние, поэтому будет возвращен новый объект, но внутренние объекты останутся прежними и мутированными.

Или мне нужно сделать что-то вроде:

function reducer(state={ byId: {}, ids: [] }, action) {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        byId: {
          ...state.byId,
          [action.id]: action.value
        },
        ids: [ ...state.ids, action.id ]
      }

    default:
      return state
  }
}

Побочные эффекты, которые я вижу при первом подходе, находятся в DevTools LogMonitor:

  • расширение подузла (например, byId ) в предыдущем состоянии покажет то же значение, что и последнее, даже если ранее это было что-то другое
  • путешествия во времени не работают

Это просто ошибка в LogMonitor или правильный второй подход? Если я добавлю state = _.cloneDeep(state) перед мутациями, все будет работать нормально, доказывая, что LogMonitor повторно использует одни и те же объекты и, следовательно, одни и те же значения.

Остальная часть приложения работает нормально, и @connect измененные представления обновляются корректно.

Самый полезный комментарий

Последний пример — это то, что вам нужно сделать. Очевидно, что это может стать несколько многословным, если вы вкладываете вещи. Есть несколько служебных библиотек, которые пытаются абстрагировать это для вас, и некоторые из них перечислены на странице Immutable Data моего списка библиотек Redux.

Также в этом помогает редукторный состав.

function byId(state = {}, action) {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        [action.id]: action.value
      }
    default:
      return state
  }
}

function ids(state = [], action) {
  switch (action.type) {
    case 'ADD':
      return [ ...state, action.id ]
    default:
      return state
  }
}

const reducer = combineReducers({
  byId,
  ids
})

Все 3 Комментарий

Нет, этот первый пример полностью мутирует состояние. Первоначальная поверхностная копия создает новый объект, но новый объект указывает на те же ссылки byId и ids , что и оригинал. Итак, когда вы делаете byId[action.id] = action.value и ids.push(action.id) , вы мутируете исходные элементы.

Последний пример — это то, что вам нужно сделать. Очевидно, что это может стать несколько многословным, если вы вкладываете вещи. Есть несколько служебных библиотек, которые пытаются абстрагировать это для вас, и некоторые из них перечислены на странице Immutable Data моего списка библиотек Redux.

В часто задаваемых вопросах Redux также есть вопрос, который охватывает правильное постоянное обновление состояния: http://redux.js.org/docs/FAQ.html#react -not-rerendering.

Последний пример — это то, что вам нужно сделать. Очевидно, что это может стать несколько многословным, если вы вкладываете вещи. Есть несколько служебных библиотек, которые пытаются абстрагировать это для вас, и некоторые из них перечислены на странице Immutable Data моего списка библиотек Redux.

Также в этом помогает редукторный состав.

function byId(state = {}, action) {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        [action.id]: action.value
      }
    default:
      return state
  }
}

function ids(state = [], action) {
  switch (action.type) {
    case 'ADD':
      return [ ...state, action.id ]
    default:
      return state
  }
}

const reducer = combineReducers({
  byId,
  ids
})

@gaearon @markerikson Спасибо. В итоге я написал редуктор высокого порядка, который управляет динамическими индексированными списками (по идентификатору).

Код: https://gist.github.com/elado/95484b754f31fcd6846c7e75de4aafe4

Была ли эта страница полезной?
0 / 5 - 0 рейтинги