【问题标题】:Correct way to add items to an array stored in React state with useState hook?使用 useState 钩子将项目添加到以 React 状态存储的数组的正确方法?
【发布时间】:2020-07-31 02:08:54
【问题描述】:

我需要将项目连接到存储在 React 组件状态中的数组。我有一个关于 stackblitz 的示例,我无法理解为什么数组没有增长,因为我使用扩展运算符添加元素以连接到现有数组。任何帮助表示赞赏

链接:https://stackblitz.com/edit/react-usestate-example-ebzt6g?file=index.js

import React from 'react';
import { useState, useEffect } from 'react';
import { render } from 'react-dom';
import './style.css';

const App = () => {

    const [name, setName] = useState('React');
    const [coords, setCoords] = useState([]);

    const success = (position) => {
        // setCoords(coords.concat(position.coords))
        setCoords([
            ...coords,
            position.coords
        ])
        console.log("success! position=", position);
    }

    useEffect(() => {
        console.log("useEffect -> coords =", coords);
    });

    useEffect(() => {
        setInterval(() => {
            success({coords : {latitude: Math.random()*51, longitude: Math.random()*2.6}});
        }, 5000);
    }, []);

    return (
    <p>example to demonstrate growing an array stored with React usestate hook</p>
    )
}

render(<App />, document.getElementById('root'));


【问题讨论】:

  • 我认为新值已添加到状态中,但您正在记录 stale closure。您可以返回以下 jsx 来验证它是否有效:&lt;pre&gt;{JSON.stringify(coords)}&lt;/pre&gt;

标签: arrays reactjs use-state


【解决方案1】:
useEffect(() => {
  setInterval(() => {
    success({coords : {latitude: Math.random()*51, longitude: Math.random()*2.6}});
  }, 5000);
}, []);

作为第二个参数的空数组告诉 react 只创建一次这个效果,并且永远不会更新它。当它被创建时,它在其闭包中引用了成功函数,而成功函数又引用了coords。由于这都是第一次渲染,coords 是一个空数组。

因此,每次调用 success 时,都会将新坐标添加到该空数组并调用 setCoords。数组永远不会增长,因为您的起点始终是空数组。而且你永远不会看到新的数组,因为它们只存在于以后的渲染中。

最简单的解决方法是使用 setCoords 的函数版本。 React 会调用函数并传入坐标的最新值

const success = (position) => {
  setCoords(prevCoords => {
    return [
      ...prevCoords,
      position.coords
    ]
  })
}

【讨论】:

  • 很好的答案,我看到成功变成了一个陈旧的闭包,因为它永远不会被重新创建(效果运行一次)。我以为只有日志在记录旧数据。
  • 很好的解释!但从概念上讲,setCoords 的函数版本如何解决这个问题?
  • @ehutchllew 问题是代码使用了一个陈旧的闭包变量,所以这个修复改变了代码,因此根本不再需要这个变量。相反,可以通过另一种方式获取数据(具体来说,React 实现了 setState 以便它将以最近的状态传递)
  • @NicholasTower 啊好吧,这是有道理的。太棒了,我感谢您的回复!我已经习惯了 OOP,像这样的函数式范例需要我一分钟才能理解。
【解决方案2】:

感谢 Nicholas Tower 的正确答案。

const success = (position) => {
  setCoords(prevCoords => {
    return [
      ...prevCoords,
      position.coords
    ]
  })
}

解决了这个问题。

【讨论】:

    【解决方案3】:

    好吧,我遇到了这个问题,感谢帮助我弄清楚如何解决这个问题的人,首先你必须克隆坐标,然后你将新坐标添加到克隆中,然后设置新的克隆坐标到这样的状态:

     const success = (position) => {
      let clonedCoords = [...coords];
      setCoords([...clonesCoords, position.coords]);
      console.log("success! position=", position);
    };
    

    这应该可以,如果不行你可以回复我可以帮助你更多

    【讨论】:

    • 他们已经在复制坐标了。这不是问题。
    • 他说函数成功执行时列表没有更新,我遇到了类似的问题,这就是我修复它的方法
    • 我相信你说这解决了一个类似的问题。但这在这里无济于事。
    • 那么你能解释一下为什么吗?这也可以通过在 setCoords 中添加一个函数来解决,以便它将旧状态作为参数,但这应该是一样的,为什么
    • well then can you explain why ? 是的,您可以在我发布的答案中看到我的完整解释。但简短的版本:变量coords 始终是一个空数组,无论这段代码运行多少次。所以第一次没问题,因为你想复制一个空数组,但是之后就不行了,因为你想复制最近的数组,而不是一个空数组。
    猜你喜欢
    • 2023-03-07
    • 2023-03-14
    • 2020-06-24
    • 2021-04-04
    • 2019-11-08
    • 1970-01-01
    • 2021-03-16
    • 2020-04-29
    • 2019-08-06
    相关资源
    最近更新 更多