将 useState setter 函数设置为 useEffect 内的数组时渲染过多

时间:2021-02-26 03:09:50

标签: reactjs

将状态设置为 useEffect 内的原始值工作正常,而将其设置为数组/对象会导致我无法理解的多次渲染。我想知道是什么依赖导致它多次渲染。你能解释一下吗?

import React, { useEffect, useState } from 'react'

export const UseEffectSetStateError = () => {

    const [arr, setArr] = useState([1, 2, 3]);

    useEffect(() => {

        setArr([4, 5, 6]) // this gives error
        // setArr(0)      // commenting above line and uncommenting this works fine 

    }, [arr])           

    return (
        <div>

        </div>
    )
}

enter image description here

2 个答案:

答案 0 :(得分:3)

当你这样做

setArr(0)

新的 arr 状态是 === 到状态中的先前值(在第一个效果挂钩运行之后)。 React 检测到这一点并在所有新状态值 === 到旧状态值时跳过重新渲染,因此不会发生进一步的渲染,因此不会再次调用效果回调。

相反,运行

setArr([4, 5, 6])

总是将 new 数组放入状态。每次效果挂钩运行时,您都在创建一个全新的数组并将其放入状态。

console.log([1, 2] === [1, 2]);

它们不是 ===,所以 React 会重新渲染,导致无限循环。

只是为了好奇,如果你这样做了

const someArr = [4, 5, 6];
export const UseEffectSetStateError = () => {
  // ..
  useEffect(() => {
     setArr(someArr);

不会有重新渲染循环,因为在这里,新的集合数组是旧集合数组的===someArr === someArr 状态,因此在第二次运行效果回调后将跳过重新渲染。

答案 1 :(得分:1)

添加到 CertainPerformance 的答案中,您为什么要使用“arr”作为依赖项。从它的外观来看,您不是在每次 arr 的值发生变化时都试图触发该函数,对吗?您需要定义一个状态变量来告诉您的 useEffect 运行。如果你能更好地解释你的用例,我可以提供一个具体的例子。但我会说使用类似的东西:

const [triggerUseEffect, setTriggerUseEffect] = useState(0)

useEffect(() => {
    setArr([4,5,6])
}, [triggerUseEffect])

在应该触发 useEffect 的函数内,添加这一行:

setTriggerUseEffect(p => p+1);