在带有数组的单个函数中多次调用 useVal - 意外行为

Calling `useVal` several times in a single function with arrays - unexpected behavior

我在一次函数调用中多次调用 useArr 函数。每次调用 useArr,我都会将一个新值推送到现有的 arr 函数。我用 pause 函数错开每个调用。

不是以逐步间隔方式呈现 abcde 的字符串,而是简单地覆盖前一个字母。我对引擎盖下的钩子的理解不是很好,所以如果有人能提供见解,我将不胜感激。

为了说明我为什么要编写这段非常规代码,我正在尝试模拟 websocket 如何与应用程序交互,如果有人想知道:)

const App = () => {
  const [arr, useArr] = useState([])
  return (
    <div>
      {arr}
      <button onClick={increment}>Click meh</button>
    </div>
  )
  async function increment() {
    useArr([...arr, 'a'])
    await pause()
    useArr([...arr, 'b'])
    await pause()
    useArr([...arr, 'c'])
    await pause()
    useArr([...arr, 'd'])
    await pause()
    useArr([...arr, 'e'])
    await pause()
  }
  async function pause() {
    return new Promise(_=>setTimeout(_, 500))
  }
}

export { App }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

tl;dr:您应该使用 functional update 语法。

这实际上更多地是关于理解 JavaScript 闭包而不是关于钩子。为了演示发生了什么,这里有一些基于您的 increment 方法的代码,但没有任何挂钩 - 只是普通的 JavaScript.

  async function increment() {
    const arr = [];
    let nextArr = undefined;
    nextArr = [...arr, 'a'];
    await pause()
    nextArr = [...arr, 'b'];
    await pause()
    nextArr = [...arr, 'c'];
    await pause()
    nextArr = [...arr, 'd'];
    await pause()
    nextArr = [...arr, 'e'];
    await pause()
  }

在这个函数的最后,你期望 nextArr 的值是多少? ['a', 'b', 'c', 'd', 'e']['e'](提示:您已经在您的应用中看到了结果)

nextArr 表示您传递给您所在州的内容 setter.

作为旁注,我建议您使用 setArr 的命名约定而不是 useArr 作为 setter 变量名。 useX 应保留用于自定义挂钩 -- 不用于状态 setters.

你打算做的是类似下面的事情:

  async function increment() {
    const arr = [];
    let nextArr = undefined;
    nextArr = [...arr, 'a'];
    await pause()
    nextArr = [...nextArr, 'b'];
    await pause()
    nextArr = [...nextArr, 'c'];
    await pause()
    nextArr = [...nextArr, 'd'];
    await pause()
    nextArr = [...nextArr, 'e'];
    await pause()
  }

此代码利用前一个值创建下一个值。 functional update 语法可用于获得此效果。使用我建议的功能更新语法和命名更改,您的 increment 函数将如下所示:

  async function increment() {
    setArr(prevArr => [...prevArr, 'a'])
    await pause()
    setArr(prevArr => [...prevArr, 'b'])
    await pause()
    setArr(prevArr => [...prevArr, 'c'])
    await pause()
    setArr(prevArr => [...prevArr, 'd'])
    await pause()
    setArr(prevArr => [...prevArr, 'e'])
    await pause()
  }