【问题标题】:Alter Object Array in React with useState-hook without deep copying使用 useState-hook 更改 React 中的对象数组,无需深度复制
【发布时间】:2021-12-05 03:08:40
【问题描述】:

什么是更改对象数组的最佳且简洁的方法?

我有一个看起来像这样的代码。

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
]

我在谷歌上搜索了很多,但这似乎是一个常见的主题。

这篇文章描述了使用键控对象的相同问题和解决方案,这对我没有帮助。
React Hooks useState() with Object

这篇文章支持 3rd 方库和/或深度复制,我怀疑这也不是“正确”的做法。
Whats the best way to update an object in an array in ReactJS?

这个线程还支持很多深拷贝和映射,我想我不需要(它是一个数组,我应该能够通过索引来寻址我的对象)?
How do I update states `onChange` in an array of object in React Hooks

另一个深拷贝解决方案
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>

//...

</>
})

【问题讨论】:

  • “尽量避免嵌套循环”...您没有嵌套循环。调用set_post(),无论你对回调做什么,都完全独立于你的get_post.map()回调执行

标签: javascript reactjs object use-state


【解决方案1】:

如果您只想更改第一个属性,请先从数组中提取它。

您可以使用functional updates 方法访问当前状态值并返回一个包含您想要的更改的新值。

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))

与您在your answer 中似乎想要做的事情相匹配的稍微不同的版本是

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
})

【讨论】:

  • 这很干净,有什么方法可以将它应用到索引 x 上吗?
  • @RustyJames 我已经更新了我的答案
  • 我明白了。这是地图解决方案的一个很好的例子,而且很公平,它可能是这样做的唯一方法。你明白为什么我会得到我在基于索引的解决方案中得到的结果吗?
  • @RustyJames 因为赋值操作的结果是您设置为数组中最后一个元素的赋值。你基本上得到了const val = "This is index zero"; get_post[0].content = val; get_post.push(val);
  • 感谢您明确表示,我仍然很好奇是否有任何其他方法可以在没有地图的情况下执行此操作。
【解决方案2】:

我找到了一个行之有效的解决方案!
我没有在其他地方看到此帖子,因此可能会很有趣。

要通过索引更改或添加键/值到数组中的对象,只需执行以下操作:

    <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 Docs,可以对状态进行批处理和缓冲以提高性能

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)

因此,这应该是一个非常好的解决方案。

【讨论】:

  • 请参阅Using State Correctly 了解为什么您不应该这样做。这个工作的唯一原因是因为你没有等待第一个set_post申请。
  • 根据文档,我知道 React 是“批处理 setState 以获得性能”并且“setState 可能是异步的”。但是即使是批量,它仍然不应该改变第一次推送的值吗?它也适用于多个值,因此它不仅仅是第一个 set_post。
猜你喜欢
  • 2021-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 2014-11-03
  • 2021-11-13
相关资源
最近更新 更多