对数组使用 setState 时无限循环
Infinite Loop when using setState for array
我想在数组中存储 4 个“hi”。而不是:
strArr.push('hi');
strArr.push('hi');
strArr.push('hi');
strArr.push('hi');
我这样做了:
for(let i = 0; i<4; i++){
setStrArr([...strArr, "hi"])
}
但是,我收到此错误:错误:重新呈现太多。 React 限制渲染次数以防止无限循环
我不知道哪里出了问题,我想知道它是否在 i=3 时没有到达。所以我做了一个检查:
for(let i = 0; i<4; i++){
setStrArr([...strArr, "hi"])
if(i==3){
console.log("done")
}
}
'i'的值确实达到了3,但为什么我的代码又运行了?
这是我的代码:
function MyApp(){
const [strArr, setStrArr] = useState([]);
for(let i = 0; i<4; i++){
setStrArr([...strArr, "hi"])
if(i==3){
console.log("done")
}
}
return(
<div>
</div>
)
}
我相信您可能遇到了问题,因为调用 setStringArray
是 'side effect'。
这将导致函数组件无限地 re-rendered,因为钩子已经更新了组件的状态,导致 re-render 然后无限地更新状态。
本质上,您不应该尝试在同一行中读取和更新 strArray
。
在完全填充数组后,您应该只调用 setStrArr
一次。
我认为您还应该考虑使用 useEffect
挂钩来处理此类行为。
如果给定的参数(strArray
在这种情况下)发生变化,它传递的最后一个参数告诉 React 仅 运行 此 useEffect
钩子内部的代码。
这个钩子是为你想要在你的组件中有'side effects'而设计的。
所以也许你可以尝试类似的方法来防止你的无限 re-renders:
function MyApp(){
const [strArr, setStrArr] = useState([]);
useEffect(() => {
const fourHiArray = [];
for(let i = 0; i<4; i++){
fourHiArray = ([...fourHiArray, "hi"])
if(i==3){
console.log("done")
}
}
setStrArr(fourHiArray);
}, [strArr]);
return(
<div>
</div>
)
}
在重新渲染时会调用整个函数 MyApp,因此在每次重新渲染时,您的循环都会重新开始。如果只想调用一次,在useEffect中调用。像这样
useEffect(() => {*your code here*}, []}
使用空数组作为第二个参数的 useEffect 仅在第一次渲染时调用。
另外,如果您想设置初始状态,我建议您在 useState(['hi','hi','hi','hi'])
添加到其他答案中,因为您正在执行 同步 代码,所以我会使用 useLayoutEffect 挂钩。 useLayoutEffect 运行,React 等待它完成。这对于等待反应很好,因为代码都是同步的,并且它可以防止您的组件在屏幕上“闪烁”,因为渲染完成后会调用 useEffect。
function MyApp(){
const [strArr, setStrArr] = useState([]);
useLayoutEffect(() => {
let fourHiArray = [];
for(let i = 0; i<4; i++){
fourHiArray = ([...fourHiArray, "hi"])
if(i==3){
console.log("done")
}
}
setStrArr(fourHiArray);
}, []);
return(
<div>
</div>
)
}
我想在数组中存储 4 个“hi”。而不是:
strArr.push('hi');
strArr.push('hi');
strArr.push('hi');
strArr.push('hi');
我这样做了:
for(let i = 0; i<4; i++){
setStrArr([...strArr, "hi"])
}
但是,我收到此错误:错误:重新呈现太多。 React 限制渲染次数以防止无限循环
我不知道哪里出了问题,我想知道它是否在 i=3 时没有到达。所以我做了一个检查:
for(let i = 0; i<4; i++){
setStrArr([...strArr, "hi"])
if(i==3){
console.log("done")
}
}
'i'的值确实达到了3,但为什么我的代码又运行了?
这是我的代码:
function MyApp(){
const [strArr, setStrArr] = useState([]);
for(let i = 0; i<4; i++){
setStrArr([...strArr, "hi"])
if(i==3){
console.log("done")
}
}
return(
<div>
</div>
)
}
我相信您可能遇到了问题,因为调用 setStringArray
是 'side effect'。
这将导致函数组件无限地 re-rendered,因为钩子已经更新了组件的状态,导致 re-render 然后无限地更新状态。
本质上,您不应该尝试在同一行中读取和更新 strArray
。
在完全填充数组后,您应该只调用 setStrArr
一次。
我认为您还应该考虑使用 useEffect
挂钩来处理此类行为。
如果给定的参数(strArray
在这种情况下)发生变化,它传递的最后一个参数告诉 React 仅 运行 此 useEffect
钩子内部的代码。
这个钩子是为你想要在你的组件中有'side effects'而设计的。
所以也许你可以尝试类似的方法来防止你的无限 re-renders:
function MyApp(){
const [strArr, setStrArr] = useState([]);
useEffect(() => {
const fourHiArray = [];
for(let i = 0; i<4; i++){
fourHiArray = ([...fourHiArray, "hi"])
if(i==3){
console.log("done")
}
}
setStrArr(fourHiArray);
}, [strArr]);
return(
<div>
</div>
)
}
在重新渲染时会调用整个函数 MyApp,因此在每次重新渲染时,您的循环都会重新开始。如果只想调用一次,在useEffect中调用。像这样
useEffect(() => {*your code here*}, []}
使用空数组作为第二个参数的 useEffect 仅在第一次渲染时调用。
另外,如果您想设置初始状态,我建议您在 useState(['hi','hi','hi','hi'])
添加到其他答案中,因为您正在执行 同步 代码,所以我会使用 useLayoutEffect 挂钩。 useLayoutEffect 运行,React 等待它完成。这对于等待反应很好,因为代码都是同步的,并且它可以防止您的组件在屏幕上“闪烁”,因为渲染完成后会调用 useEffect。
function MyApp(){
const [strArr, setStrArr] = useState([]);
useLayoutEffect(() => {
let fourHiArray = [];
for(let i = 0; i<4; i++){
fourHiArray = ([...fourHiArray, "hi"])
if(i==3){
console.log("done")
}
}
setStrArr(fourHiArray);
}, []);
return(
<div>
</div>
)
}