Redux: 问题:reducer 状态下内部对象的突变

创建于 2016-04-15  ·  3评论  ·  资料来源: reduxjs/redux

这是一个有效的 redux reducer 吗?

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 ed 视图可以正确更新。

最有用的评论

后一个示例是您需要做的。 显然,如果您要嵌套内容,这可能会有些冗长。 有几个实用程序库试图为您抽象,我在我的 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条评论

不,第一个例子绝对是在改变状态。 最初的浅拷贝创建了一个新对象,但新对象指向与原始对象相同的byIdids引用。 因此,当您执行byId[action.id] = action.valueids.push(action.id)时,您正在改变原始项目。

后一个示例是您需要做的。 显然,如果您要嵌套内容,这可能会有些冗长。 有几个实用程序库试图为您抽象,我在我的 Redux 库列表的不可变数据页面中列出了其中的一些。

Redux FAQ 也有一个问题,涵盖正确更新状态不变: http: //redux.js.org/docs/FAQ.html#react -not-rerendering。

后一个示例是您需要做的。 显然,如果您要嵌套内容,这可能会有些冗长。 有几个实用程序库试图为您抽象,我在我的 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谢谢。 我最终编写了一个管理动态索引列表(按 ID)的高阶归约器

代码: https ://gist.github.com/elado/95484b754f31fcd6846c7e75de4aafe4

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

olalonde picture olalonde  ·  3评论

dmitry-zaets picture dmitry-zaets  ·  3评论

captbaritone picture captbaritone  ·  3评论

CellOcean picture CellOcean  ·  3评论

cloudfroster picture cloudfroster  ·  3评论