当只更新状态的一部分时,我需要克隆我的状态多深?

Ami*_*mir 5 reactjs redux react-redux

直到最近,我一直只使用 lodash 的 cloneDeep 来复制我的状态,然后更改值并返回克隆的状态。例如像这样:

这将是我的初始状态:

{
    "id": 1213,
    "title": "Some title...",
    "pages": {
        "page1": {
            "id": 459,
            "title": "Some Page title...",
            "fields": {
                "field_1": {
                    "title": "My field",
                    "type": "text",
                    "value": "my text value..."
                },
                "field_2": {
                    "title": "My field 2",
                    "type": "text",
                    "value": "my text two value..."
                },
                "field_3": {
                    "title": "My field 3",
                    "type": "text",
                    "value": "my text value..."
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我想更新field_2的值。

我的 redux 减速器看起来像这样:

import cloneDeep from 'lodash/fp/cloneDeep';

export default function reducer(state, action) {
  const {type, payload} = action;
  switch (type) {
    case 'UPDATE_FIELD_VALUE': {
      const { pageIdent, fieldIdent, newValue } = payload;
      // This is what I'm doing right now....
      const newState = cloneDeep(state);
      newState.pages[pageIdent]fields[fieldIdent]value = newValue;
      return newState;
      // Instead could I do this?
      return {
        ...state,
        state.pages[pageIdent]fields[fieldIdent]value = newValue;
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

所以,我读到我并不总是需要进行深度克隆……但在其他地方我读到你不能返回同一个对象,你必须始终返回新对象。那么这样做的正确方法是什么?

mar*_*son 5

是的,不要那样做。引用Redux FAQ 关于你是否应该深度克隆 state

不变地更新状态通常意味着制作浅拷贝,而不是深拷贝。浅拷贝比深拷贝快得多,因为需要复制的对象和字段更少,而且它有效地归结为移动一些指针。

但是,您确实需要为受影响的每个嵌套级别创建一个复制和更新的对象。尽管这不应该特别昂贵,但这是您应该尽可能保持状态规范化和浅层的另一个很好的理由。

常见的 Redux 误解:您需要深度克隆状态。现实:如果里面的东西没有改变,保持它的引用不变!

所以,你不需要“深克隆”,你需要“嵌套的浅克隆”。

深度克隆在两个方面对性能不利:克隆所有内容需要更多的工作,并且新的对象引用将导致 UI 更新值实际上并未更改的数据(但新引用使 UI认为某些内容发生了变化)。

您应该阅读Redux 文档页面上的“不可变更新模式”。这是该页面的嵌套状态更新示例:

function updateVeryNestedField(state, action) {
    return {
        ....state,
        first : {
            ...state.first,
            second : {
                ...state.first.second,
                [action.someId] : {
                    ...state.first.second[action.someId],
                    fourth : action.someValue
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您发现这太乏味或太痛苦,您应该更改状态的结构以使其更平坦,或者您可以使用许多不可变的更新实用程序库之一来为您处理更新过程。