微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用数组属性设置 React 或 Recoil 状态对象的更简单方法

如何解决使用数组属性设置 React 或 Recoil 状态对象的更简单方法

希望有人能用更简单的方法帮助我更新更复杂的对象/阵列上的后坐力状态。我主要是一名 C# 开发人员,但正在尝试学习一些不错的 javascript 编码方法。这看起来很丑陋且过于复杂,就像我的代码目前的样子。

由于状态实例是只读的,我不能直接更改它的值。使用下划线克隆方法甚至不会改变这一点。

所以这是我的简化对象,在现实生活中它们有很多不相关的属性

interface IDeviceAttributeValue {
  /** The unique value key
  id: string;
  /** The attribute value */
  value: any;
}

interface IDeviceAttribute {
  /** A unique key to identify the attribute. normally the OSC address of the setting is used */
  key: string;
  /** The list of attribute values */
  values: IDeviceAttributeValue[];
}

在 React 中我有状态声明 const [attribute,setAttribute] = useState(props.attribute as IDeviceAttribute);

或者其他一些有 Recoil 状态的地方:const [deviceAttributeState,setDeviceAttributeState] = useRecoilState(recoilDeviceAttributeState);

代码中的某处,我需要更改值数组上的值并更新状态。在 React 状态和 Recoil 状态的两种情况下,“getter”实例都是只读/常量。

我最终是这样的:

... code calculating a new value for existing value in editedSetting: IDeviceAttributeValue
...

// Now update state,first find the element in the array
let index = attribute.values.findindex(l => l.id === editedSetting.id);
if (index !== -1) {
  let newValueItem = {
     ...attribute.values[index],value: newValue
  }
  setAttribute({
    ...attribute,values: [...attribute.values.slice(0,index - 1),newValueItem,...attribute.values.slice(index + 1)]
  })
}

这么多行代码用于一个简单的状态更新!我敢肯定,对于某些人来说,这是一项非常微不足道的任务,可以做得更优雅:-)

感谢您的帮助和时间

解决方法

如果这在您的代码中很常见,那么您可以将更新逻辑提取到自定义挂钩。我在考虑类似的事情

function useDeviceAttribute(initialValue: IDeviceAttribute) {
   const [attribute,setAttribute] = useState(initialValue);
   
   const updateAtId = (id: number,newValue: any) => {
      let index = attribute.values.findIndex(l => l.id === id);
      if (index !== -1) {
        let newValueItem = {
           ...attribute.values[index],value: newValue
        }
        setAttribute({
          ...attribute,values: [...attribute.values.slice(0,index - 1),newValueItem,...attribute.values.slice(index + 1)]
        })
      }
   };

   return [attribute,updateAtId];
}

所以你的组件代码应该是这样的

function YourComponent(props) {
   const [attribute,updateAtId] = useDeviceAttribute(props.attribute);
   //
   // your component code goes here
   //
   // ... code calculating a new value for existing value in editedSetting: IDeviceAttributeValue
   /// ...
   // Now update state,first find the element in the array
   updateAtId(editedSetting.id,newValue);
}
,

好的,如果不使用扩展运算符并处理深度更新,似乎无法更新基于对象/数组的状态,因为浅层属性更新仅适用于顶层。

这意味着您必须注意提供当前状态的现有属性值,并设置要并行更改的值,并且您需要在每个嵌套级别上执行此操作。

我在这里找到了一个很好的问答,提供了示例:blog

因此,在我的情况下,我最终得到了这样的代码,用于更新具有数组属性(设置)的对象,并为数组中的一个特定元素使用新值:

setEditedDeviceState(curVal => ({
   ...curVal,settings: curVal.settings.map(
     el => el.key === attribute.key ? attribute : el
   )
}));

我必须指出,我发现这在...中很痛苦,并且很容易在您的数据模型中引入错误。 如果这是语言本身的缺失或 react(后坐力、redux 或其他)状态的实现,则可能需要进一步讨论。但似乎这就是你目前必须忍受的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。