【问题标题】:Pass by reference assignment mutates redux state通过引用赋值改变 redux 状态
【发布时间】:2018-02-04 15:14:29
【问题描述】:

我有一个带有项目菜单的应用程序,并且在某些时候,用户可能会编辑项目的值。当用户这样做时,我会在单独的状态分支中创建该项目的副本,而不是更改原始菜单项。所以我的减速器看起来像这样:

const menuReducer = (state = [], action) => {
  switch (action.type) {
    case ADD_ITEM:
      return [...state, {id: action.itemId, propA: action.itemPropA, propB: action.itemPropB}]
  }
}

const editingMenuItem = (state = {}, action) => {
  switch (action.type) {
    case SET_EDIT_ITEM:
      return {id: action.id, propA: action.itemPropA, propB: action.itemPropB}
    case EDIT_ITEM:
      return {id: state.id, propA: action.itemPropA, propB: action.itemPropB}
  }
}

有人选择他们想要编辑一个项目,这会导致dispatchEditItem thunk 触发并在状态树中创建一个副本:

const dispatchEditItemThunk = itemId => (dispatch, getState) => {
  const item = _.find(getState().menu, ['id', itemId]);
  dispatch(setEditItem(item.id, item.propA, item.propB))
}

然后当有人想要编辑一个道具时,editingThunk 被调度:

const editingThunk = (itemId, propName) => (dispatch, getState) => {
  let activeItem = getState().editingMenuItem;
  // someValue is generated here
  activeItem[propName] = someValue
  dispatch(editItem(activeItem.propA, activeItem.propB))
}

问题在于,当activeItem[propName] = someValue 发生时,这会更改 menuReducer 数组中包含的项目的值。我假设因为所有内容都是通过引用传递的,并且所有引用导致 menuReducer 中的原始值。但是,这不是我期望的工作方式。我的假设是调用getState 将返回状态的深层副本,并且不允许这些意外突变。

这是一个错误吗?如果不是,是否有一种避免这种情况的首选方式来编写 thunk?在我的实际用例中,menuItem 中的道具结构非常复杂,在 thunk 中创建一个 activeItem 并在分派到状态树之前改变它的值是很方便的。这样做很糟糕吗?

【问题讨论】:

  • “这会导致 dispatchEditItem thunk 触发并在状态树中创建一个副本” - 我没有看到该代码的哪个部分应该创建一个副本。
  • edtingMenuItem reducer 是副本。 state.menu 是 menuItems 的列表,state.editingMenuItem 应该是该列表中某个项目的副本。 setEditItem 填充该副本的值。

标签: javascript redux redux-thunk


【解决方案1】:

这不是一个错误,并且非常不鼓励改变 state 对象。您可以使用 Object.assignJSON.stringify 方法创建对象的深层副本,如此处 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign 所述(示例部分)。 如果 Redux 要在每个 dispatch 调用上创建 state 的深层副本,它可能会更安全,但也会慢得多。

【讨论】:

    猜你喜欢
    • 2015-11-27
    • 2021-03-15
    • 2019-03-19
    • 2019-01-30
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 2019-02-20
    • 2019-03-16
    相关资源
    最近更新 更多