使用 useState-hook 更改 React 中的对象数组,无需深度复制
Alter Object Array in React with useState-hook without deep copying
更改对象数组的最佳且简洁的方法是什么?
我有一个看起来像这样的代码。
const [get_post, set_post] = useState([
{name: "First"},
{name: "Second"},
{name: "Third"},
])
我想在某个索引上添加和编辑键。所以我这样做:
<button onClick={()=>
set_post([...get_post, get_post[0].content = "This is index zero" ])
}> Manipulate! </button>
我的结果是这样的:
[
{"name": "First", "content": "This is index zero"},
{"name": "Second"},
{"name": "Third"},
"This is index zero" <-- This line is the problem
]
我在谷歌上搜索了很多次,但这似乎是一个常见的主题。
这个 post 用键控对象描述了相同的问题和解决方案,这对我没有帮助。
这个 post 支持第 3 方库 and/or 深度复制,我怀疑这也不是“正确”的做法。
这个线程还支持很多深拷贝和映射,我想我不需要(它是一个数组,我应该可以通过索引来寻址我的对象)?
另一种深拷贝解决方案
https://codereview.stackexchange.com/questions/249405/react-hooks-update-array-of-object
清单还在继续...
基本上我想要没有额外行的结果,
如果可能的话:
- 没有深度复制状态以重新注入。
- 没有第 3 方库。
- 不使用键控对象。
- 运行 set_post.
内没有 map/filter 循环
编辑:setPost 中不需要 map 的原因。
在我的特定场景中,呈现 getPost 的模块已经是一个映射循环。试图避免嵌套循环。
(我的逻辑简化了)
const [get_post, set_post] = useState([
{name: "First"},
{name: "Second"},
{name: "Third"},
])
//Render module
//Fixed numbers of controllers for each Object in Array.
get_post.map((post, index)=> {
<>
<button onClick={()=>
set_post([...get_post, get_post[index].content = "Content 1" ])}
}>
Controller 1
</button>
<button onClick={()=>
set_post([...get_post, get_post[index].content = "Content 2" ])}
}>
Controller 2
</button>
<button onClick={()=>
set_post([...get_post, get_post[index].content = "Content 3" ])}
}>
Controller 3
</button>
//...
</>
})
如果您只想更改第一个 属性,请先从数组中提取它。
您可以使用 functional updates 方法访问当前状态值,并 return 一个具有您想要的更改的新值。
set_post(([ first, ...others ]) => [{
...first,
content: "This is index zero"
}, ...others])
要更改任何特定索引,您可以map将当前数组更改为一个新数组,在到达目标索引时为它创建一个新对象
let x = the_target_index
set_post(posts => posts.map((post, i) => i === x ? {
...post,
content: `This is index ${x}`
} : post))
与您在 中似乎想要做的事情相匹配的稍微不同的版本是
set_post(posts => {
posts[x] = { ...posts[x], content: `This is index ${x}` }
// or even something like
// posts[x].content = `This is index ${x}`
return [...posts] // clone the array
})
我找到了一个有效的解决方案!
我没有在其他地方看到这个帖子,所以研究一下可能会很有趣。
要按索引更改或添加 key/value 到数组中的对象,只需执行以下操作:
<button onClick={() => {
set_post( [...get_post , get_post[index].content = "my content" ] )
set_post( [...get_post ] ) //<-- this line removes the last input
}
}>
正如 Phil 所写,前面的代码被解释为:
const val = "This is index zero";
get_post[0].content = val;
get_post.push(val);
这似乎删除了最新的 get_post.push(val)
根据 React 文档,可以对状态进行批处理和缓冲以实现性能
https://reactjs.org/docs/state-and-lifecycle.html#using-state-correctly
当 React 批处理时 set_post 它应该表现得像这样。
如果一行命令
set_post( [...get_post , get_post[index].content = "my content" ] )
给予
const val = "This is index zero";
get_post[0].content = val;
get_post.push(val);
双重注入将触发缓冲区并在 array.push() 结束时重新注入状态。像这样。
var buffer = get_post
buffer[0].content = val
//Other updated to get_post...
get_post = buffer //(not push)
至此,这应该是一个完美的解决方案。
更改对象数组的最佳且简洁的方法是什么?
我有一个看起来像这样的代码。
const [get_post, set_post] = useState([
{name: "First"},
{name: "Second"},
{name: "Third"},
])
我想在某个索引上添加和编辑键。所以我这样做:
<button onClick={()=>
set_post([...get_post, get_post[0].content = "This is index zero" ])
}> Manipulate! </button>
我的结果是这样的:
[
{"name": "First", "content": "This is index zero"},
{"name": "Second"},
{"name": "Third"},
"This is index zero" <-- This line is the problem
]
我在谷歌上搜索了很多次,但这似乎是一个常见的主题。
这个 post 用键控对象描述了相同的问题和解决方案,这对我没有帮助。
这个 post 支持第 3 方库 and/or 深度复制,我怀疑这也不是“正确”的做法。
这个线程还支持很多深拷贝和映射,我想我不需要(它是一个数组,我应该可以通过索引来寻址我的对象)?
另一种深拷贝解决方案
https://codereview.stackexchange.com/questions/249405/react-hooks-update-array-of-object
清单还在继续...
基本上我想要没有额外行的结果,
如果可能的话:
- 没有深度复制状态以重新注入。
- 没有第 3 方库。
- 不使用键控对象。
- 运行 set_post. 内没有 map/filter 循环
编辑:setPost 中不需要 map 的原因。
在我的特定场景中,呈现 getPost 的模块已经是一个映射循环。试图避免嵌套循环。
(我的逻辑简化了)
const [get_post, set_post] = useState([
{name: "First"},
{name: "Second"},
{name: "Third"},
])
//Render module
//Fixed numbers of controllers for each Object in Array.
get_post.map((post, index)=> {
<>
<button onClick={()=>
set_post([...get_post, get_post[index].content = "Content 1" ])}
}>
Controller 1
</button>
<button onClick={()=>
set_post([...get_post, get_post[index].content = "Content 2" ])}
}>
Controller 2
</button>
<button onClick={()=>
set_post([...get_post, get_post[index].content = "Content 3" ])}
}>
Controller 3
</button>
//...
</>
})
如果您只想更改第一个 属性,请先从数组中提取它。
您可以使用 functional updates 方法访问当前状态值,并 return 一个具有您想要的更改的新值。
set_post(([ first, ...others ]) => [{
...first,
content: "This is index zero"
}, ...others])
要更改任何特定索引,您可以map将当前数组更改为一个新数组,在到达目标索引时为它创建一个新对象
let x = the_target_index
set_post(posts => posts.map((post, i) => i === x ? {
...post,
content: `This is index ${x}`
} : post))
与您在
set_post(posts => {
posts[x] = { ...posts[x], content: `This is index ${x}` }
// or even something like
// posts[x].content = `This is index ${x}`
return [...posts] // clone the array
})
我找到了一个有效的解决方案!
我没有在其他地方看到这个帖子,所以研究一下可能会很有趣。
要按索引更改或添加 key/value 到数组中的对象,只需执行以下操作:
<button onClick={() => {
set_post( [...get_post , get_post[index].content = "my content" ] )
set_post( [...get_post ] ) //<-- this line removes the last input
}
}>
正如 Phil 所写,前面的代码被解释为:
const val = "This is index zero";
get_post[0].content = val;
get_post.push(val);
这似乎删除了最新的 get_post.push(val)
根据 React 文档,可以对状态进行批处理和缓冲以实现性能
https://reactjs.org/docs/state-and-lifecycle.html#using-state-correctly
当 React 批处理时 set_post 它应该表现得像这样。
如果一行命令
set_post( [...get_post , get_post[index].content = "my content" ] )
给予
const val = "This is index zero";
get_post[0].content = val;
get_post.push(val);
双重注入将触发缓冲区并在 array.push() 结束时重新注入状态。像这样。
var buffer = get_post
buffer[0].content = val
//Other updated to get_post...
get_post = buffer //(not push)
至此,这应该是一个完美的解决方案。