使用数组属性设置 React 或 Recoil 状态对象的更简单方法
Easier way to set React or Recoil state objects with array properties
希望有人能帮助我更简单地更新我在更复杂的情况下的后坐力状态 objects/arrays。我主要是一名 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);
或者其他一些反冲状态的地方:const [deviceAttributeState, setDeviceAttributeState] = useRecoilState(recoilDeviceAttributeState);
在代码的某处,我需要更改值数组中的值并更新状态。在 React 状态和 Recoil 状态的两种情况下,'getter' 实例都是 readonly/const.
我最终得到这个:
... 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);
}
好吧,似乎没有办法更新基于 object/array 的状态而不使用扩展运算符并处理深度更新,因为浅层 属性 更新仅适用于顶层。
这意味着您必须注意提供当前状态的现有 属性 值,并设置您想要并行更改的值,并且您需要在每个嵌套级别上执行此操作。
我发现了一个很好的 q/a 在这里提供示例:
所以在我的例子中,我最终得到了这样的代码,用于使用数组 属性 (设置)更新对象,并为数组中的一个特定元素设置新值:
setEditedDeviceState(curVal => ({
...curVal,
settings: curVal.settings.map(
el => el.key === attribute.key ? attribute : el
)
}));
我必须承认,我发现这是一个痛苦的......并且很容易在您的数据模型中引入错误。
如果这是语言本身或 react(recoil、redux 或其他)状态的实现方面的不足,则可能可以进一步讨论。但似乎这就是你目前必须忍受的。
希望有人能帮助我更简单地更新我在更复杂的情况下的后坐力状态 objects/arrays。我主要是一名 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);
或者其他一些反冲状态的地方:const [deviceAttributeState, setDeviceAttributeState] = useRecoilState(recoilDeviceAttributeState);
在代码的某处,我需要更改值数组中的值并更新状态。在 React 状态和 Recoil 状态的两种情况下,'getter' 实例都是 readonly/const.
我最终得到这个:
... 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);
}
好吧,似乎没有办法更新基于 object/array 的状态而不使用扩展运算符并处理深度更新,因为浅层 属性 更新仅适用于顶层。
这意味着您必须注意提供当前状态的现有 属性 值,并设置您想要并行更改的值,并且您需要在每个嵌套级别上执行此操作。
我发现了一个很好的 q/a 在这里提供示例:
所以在我的例子中,我最终得到了这样的代码,用于使用数组 属性 (设置)更新对象,并为数组中的一个特定元素设置新值:
setEditedDeviceState(curVal => ({
...curVal,
settings: curVal.settings.map(
el => el.key === attribute.key ? attribute : el
)
}));
我必须承认,我发现这是一个痛苦的......并且很容易在您的数据模型中引入错误。 如果这是语言本身或 react(recoil、redux 或其他)状态的实现方面的不足,则可能可以进一步讨论。但似乎这就是你目前必须忍受的。