简体   繁体   English

通过引用赋值改变 redux 状态

[英]Pass by reference assignment mutates redux state

I have an app with a menu of items, and at some point a user may edit the values of the items.我有一个带有项目菜单的应用程序,在某些时候用户可以编辑项目的值。 When the user does so, I create a copy of the item in a seperate state branch instead of changing the original menu items.当用户这样做时,我会在单独的状态分支中创建项目的副本,而不是更改原始菜单项。 So my reducer looks like this:所以我的减速器看起来像这样:

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}
  }
}

Someone selects that they want to edit an item, and this causes the dispatchEditItem thunk to trigger and create a copy in the state tree:有人选择他们想要编辑一个项目,这会导致dispatchEditItem thunk 触发并在状态树中创建一个副本:

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

Then when someone wants to edit a prop, the editingThunk is dispatched:然后,当有人想要编辑道具时,将发送编辑editingThunk

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

The problem with this is that when activeItem[propName] = someValue happens, this changes the value of the item contained in the menuReducer array.这样做的问题是当activeItem[propName] = someValue发生时,这会更改 menuReducer 数组中包含的项目的值。 I'm assuming because everything is pass by reference, and all the references lead back to the original value in the menuReducer.我假设是因为一切都是通过引用传递的,并且所有引用都返回到 menuReducer 中的原始值。 However, this isn't the way I would expect this to work.但是,这不是我期望的工作方式。 My assumption would be that calling getState would return a deep copy of the state, and not allow for these kinds of accidental mutations.我的假设是调用getState将返回getState的深层副本,并且不允许这些类型的意外突变。

Is this a bug?这是一个错误吗? If it isn't, is there a preferred way of writing thunks that avoids this kind of situation?如果不是,是否有一种避免这种情况的首选编写 thunk 的方法? In my real use case, the structure of the props in the menuItem is very complex, and it is handy to create an activeItem in the thunk and mutate it's values before dispatching to the state tree.在我的实际用例中,menuItem 中道具的结构非常复杂,在分派到状态树之前,在 thunk 中创建一个activeItem并改变它的值非常方便。 Is doing this bad?这样做不好吗?

That's not a bug and mutating state object is highly discouraged.这不是一个错误,并且非常不鼓励改变state对象。 You can create a deep copy of an object using Object.assign and JSON.stringify methods as described here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign ( Examples section).您可以使用Object.assignJSON.stringify方法创建对象的深层副本,如下所述https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign示例节)。 If Redux was to create a deep copy of state on each dispatch call it could be more secure but also much slower.如果 Redux 要在每次dispatch调用时创建state的深层副本,它可能会更安全,但速度也会慢得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM