我不确切地知道它是什么,但我在尝试使用钩子对数组进行最简单的状态更新时遇到了无数问题。
我发现唯一可行的方法是使用useReducer在数组上执行单个更新,并在onClick处理程序上放置调度。在我当前的项目中,我试图在嵌套在表单提交的函数中的for循环中更新数组状态。我尝试了很多不同的解决方案,这只是我的尝试之一。
function sessionToState(session) {
let formattedArray = []
for (let i = 0; i < session.length; i++) {
formattedArray.push({ url: session[i] })
setLinksArray([...linksArray, formattedArray[i]])
}
}
// --------------------------------------------------------
return (
<div>
<form
method="post"
onSubmit={async e => {
e.preventDefault()
const session = await getURLs({ populate: true })
sessionToState(session)
await createGroup()
我想知道是否有任何我遗漏的大事,或者可能是一些关于如何使用钩子处理数组的好技巧和窍门。如果需要更多信息,请不要犹豫。谢谢。
我想知道是否有任何我想念的大事
TLDR:setLinksArray
不会在当前渲染中更新linksArray
,而是在下一个渲染中更新。
假设变量初始化如下:
const [linksArray, setLinksArray] = useState([])
一个提示在const
关键字中,linksArray
是1个渲染中的常量(这个事实不会随着let
而改变,因为它只是useState
的工作原理)。
setLinksArray()
的想法是在下一个渲染中创建一个不同的常量值。
所以for
循环类似于:
setLinksArray([...[], session0])
setLinksArray([...[], session1])
setLinksArray([...[], session2])
你会在下一个渲染中得到linksArray = [session2]
。
保持理智的最佳方法是每个渲染每个状态只调用一次setState
函数(尽管你可以有多个状态),对代码的最小改动:
function sessionToState(session) {
let formattedArray = []
for (let i = 0; i < session.length; i++) {
formattedArray.push({ url: session[i] })
}
setLinksArray(formattedArray)
}
此外,如果您需要在所有setState
函数完成其工作后执行副作用(如API调用),即在NEXT渲染之后,您将需要useEffect
:
useEffect(() => {
...do something with updated linksArray...
}, [linksArray])
从嵌套函数调用中调用状态setter时,您应该使用functional update form of setState
。在你的情况下,它将是:
setLinksArray(linksArray => [...linksArray, formattedArray[i]])
目前尚不清楚你遇到了什么样的问题,但上面的修复将使你免于意外的linksArray
状态。
这也适用于任何状态,不仅适用于数组。
性能方面,你不应该每次迭代调用setState
。您应该使用final数组设置状态。
const sessionToState = (session) => {
setLinksArray(
session.map(sessionItem => ({url: sessionItem}))
);
}
...或者如果你想保留旧项目,你应该使用setState中的函数来做...
const sessionToState = (session) => {
setLinksArray(oldState => [
...oldState,
...session.map(sessionItem => ({url: sessionItem}))
]);
}