在带有数组的单个函数中多次调用 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()
}
我在一次函数调用中多次调用 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()
}