更新反应状态而不覆盖先前的状态

Posted

技术标签:

【中文标题】更新反应状态而不覆盖先前的状态【英文标题】:Update react state without overriding previous state 【发布时间】:2021-11-09 09:26:32 【问题描述】:

我正在尝试使用多维数组更新状态值,但我似乎无法弄清楚如何更新其中一个数组对象键值而不影响我在调度后稍后在流程中使用的先前状态值称呼。 有效负载下方的代码带有一组 id(节点),我循环遍历并更改状态对象中的唯一对象。相当直截了当,但是更新对象的多维数组而不影响状态让我感到困惑。


    UPDATE_RESTRICTION: (curState, payload) => 
    
      const updatedNodes = ...curState.layout
      const accessProfile = BpUAE.accessProfileID
    
      payload.nodes.forEach((node, index) => 
    
    
        if (typeof (updatedNodes[node].settings.bp_uae_restrictions) === 'undefined') 
          updatedNodes[node].settings.bp_uae_restrictions = ;
        
    
        if (typeof (updatedNodes[node].settings.bp_uae_restrictions[accessProfile]) === 'undefined') 
          updatedNodes[node].settings.bp_uae_restrictions[accessProfile] = ;
        
    
    
        updatedNodes[node].settings.bp_uae_restrictions[accessProfile].is_node_restricted =  JSON.parse(payload.isRestricted);

       )

    
      return layout: updatedNodes
    
    
    

如果您需要更多信息,请告诉我,感谢您提供的任何帮助。

【问题讨论】:

【参考方案1】:

检查您的退货声明,您必须包括您之前的状态并覆盖如下所示的布局。

 return ...curState, layout: updatedNodes

【讨论】:

我试过了,但没有运气。如果我在循环之前 console.log curState,它将显示我在循环内更改的新值 updatedNodes[node].settings.bp_uae_restrictions[accessProfile].is_node_restricted = JSON.parse(payload.isRestricted); 该值与以前的状态和新状态相同。 我已经尝试了一些测试,如果我注释掉循环部分并只是向对象添加一个节点,它将显示新旧状态。没有“12345”节点的旧状态和带有“12345”节点的新状态值。 UPDATE_RESTRICTION: (curState, payload) => const updatedNodes = ...curState.layout const accessProfile = BpUAE.accessProfileID updatedNodes['12345'] = true return layout: updatedNodes 【参考方案2】:

您没有正确应用不可变更新模式,您正在改变指向当前状态对象的嵌套引用。您需要创建新的对象引用并浅拷贝所有正在更新的状态。

UPDATE_RESTRICTION: (curState, payload) => 
  const updatedNodes =  ...curState.layout 
  const accessProfile = BpUAE.accessProfileID;

  payload.nodes.forEach((node, index) => 
    if (typeof (updatedNodes[node].settings.bp_uae_restrictions) === 'undefined') 
      updatedNodes[node] = 
        ...updatedNodes[node],
        settings: 
          ...updatedNodes[node].settings,
          bp_uae_restrictions: ,
        ,
      ;
    

    if (typeof (updatedNodes[node].settings.bp_uae_restrictions[accessProfile]) === 'undefined') 
      updatedNodes[node] = 
        ...updatedNodes[node],
        settings: 
          ...updatedNodes[node].settings,
          bp_uae_restrictions: 
            ...updatedNodes[node].settings.bp_uae_restrictions,
            [accessProfile]: ,
          ,
        ,
      ;
    

    // now all the new references have been created and previous
    // state shallow copied, you can update the deeply nested 
    // `is_node_restricted` property.
    updatedNodes[node].settings.bp_uae_restrictions[accessProfile].is_node_restricted = JSON.parse(payload.isRestricted);
  );

  return 
    ...curState,
    layout: updatedNodes,
  ;

更新:添加了最后一个不可变模式

  const updatedNodes =  ...curState.layout 
  const accessProfile = BpUAE.accessProfileID;

  payload.nodes.forEach((node, index) => 
    if (typeof (updatedNodes[node].settings.bp_uae_restrictions) === 'undefined') 
      updatedNodes[node] = 
        ...updatedNodes[node],
        settings: 
          ...updatedNodes[node].settings,
          bp_uae_restrictions: ,
        ,
      ;
    

    if (typeof (updatedNodes[node].settings.bp_uae_restrictions[accessProfile]) === 'undefined') 
      updatedNodes[node] = 
        ...updatedNodes[node],
        settings: 
          ...updatedNodes[node].settings,
          bp_uae_restrictions: 
            ...updatedNodes[node].settings.bp_uae_restrictions,
            [accessProfile]: ,
          ,
        ,
      ;
    

    // now all the new references have been created and previous
    // state shallow copied, you can update the deeply nested 
    // `is_node_restricted` property.
    updatedNodes[node] = 
      ...updatedNodes[node],
      settings: 
        ...updatedNodes[node].settings,
        bp_uae_restrictions: 
          ...updatedNodes[node].settings.bp_uae_restrictions,
          [accessProfile]: 
            ...updatedNodes[node].settings.bp_uae_restrictions[accessProfile],
            is_node_restricted:  JSON.parse(payload.isRestricted)
          ,
        ,
      ,
    ;
  );

  return 
    ...curState,
    layout: updatedNodes,
  ;
```

【讨论】:

感谢您的帮助。我必须更新它并将最后一个不可变模式添加到受限键。我更新了你的代码。谢谢 @DavidLabbe 啊,你知道吗,我一直犹豫不决,因为那里似乎没有更多的嵌套状态,但你是绝对正确的,也应该浅拷贝你的那部分状态为好。感谢您的编辑。如果答案解决/解决了您的问题,那么我邀请您接受它(***.com/help/someone-answers)。不要忘记为您在 SO 上找到的有用和/或有用的问题、答案和 cmets 投票。干杯,祝你好运。 不用担心。我需要你的帮助才能朝着正确的方向前进。我知道我没有得到正确的不可变模式,只需要看到正确的模式来围绕它。嵌套的部分让我发疯了……哈哈。再次感谢,非常感谢! @DavidLabbe 如果这是 redux reducer 中的一个案例,即您正在使用 redux,那么我强烈建议考虑将 redux-toolkit 集成到您的项目中。它在底层使用 ImmerJS 并允许您在减速器中编写更具可读性的代码,类似于您最初编写的代码,它会为您处理不可变的部分。 是的,我知道,但我是喜欢从头开始学习的类型。在用快捷方式替换它之前,我想完全了解它是如何工作的。话虽如此,我正处于仅使用 react 的 react redux 替换的最后阶段。到目前为止,它的效果非常好,每个人都说它做不到。如果您有兴趣,我可能需要一些测试人员?

以上是关于更新反应状态而不覆盖先前的状态的主要内容,如果未能解决你的问题,请参考以下文章

反应挂钩以根据先前的状态值更新状态[重复]

是否可以在本机反应中绘制状态栏?

在 React 中动态更新“状态”会覆盖整个状态

更新命令行输出

深入理解Eureka覆盖状态(九)

BrowserRouter 链接覆盖 onClick 事件