【问题标题】:How to handle an unchanging array in useEffect dependency array?如何处理 useEffect 依赖数组中不变的数组?
【发布时间】:2021-01-08 19:14:38
【问题描述】:

我有一个这样的组件。我想要的是 useEffect 函数在myBoolean 更改时随时运行。

我可以通过将依赖数组设置为[myBoolean] 来实现这一点。但随后我收到警告说我违反了exhaustive-deps 规则,因为我在函数内部引用了myArray。我不想违反那个规则,所以我将依赖数组设置为[myBoolean, myArray]

然后我得到一个无限循环。发生的事情是每次myArray 更改时都会触发 useEffect,这是每次,因为事实证明 myArray 来自 redux,并且在每次重新渲染时都会重新生成。而且即使数组的元素和之前的一样,React 还是使用=== 比较数组和之前的版本,结果不是同一个对象,所以不相等。

那么正确的方法是什么?如何在不违反exhaustive-deps 规则的情况下仅在myBoolean 更改时运行我的代码?

我见过this,但我仍然不确定这种情况下的解决方案是什么。

const MyComponent = ({ myBoolean, myArray }) => {
  const [myString, setMyString] = useState('');

  useEffect(() => {
    if(myBoolean) {
      setMyString(myArray[0]);
    }
  }, [myBoolean, myArray]
}

【问题讨论】:

    标签: javascript arrays reactjs redux


    【解决方案1】:

    我有个主意要保存previous props。然后我们将在稍后实现功能比较previous props。比较值将用于决定处理 useEffectno dependency 中的功能更改。

    它会占用更多的计算和内存。只是一个想法。

    这是我的例子:

    function usePrevious(value) {
        const ref = useRef();
        useEffect(() => {
            ref.current = value;
        });
    
        return ref.current;
    }
    
    function arrayEquals(a, b) {
        return Array.isArray(a) &&
            Array.isArray(b) &&
            a.length === b.length &&
            a.every((val, index) => val === b[index]);
    }
    
    const MyComponent = ({ myBoolean, myArray }) => {
        const [myString, setMyString] = useState('');
        const previousArray = usePrevious(myArray);
        const previousBoolean = usePrevious(myBoolean);
    
        const handleEffect = () => {
            console.log('child-useEffect-call-with custom compare');
    
            if(myBoolean) {
                setMyString(myArray[0]);
            }
        };
    
        //handle effect in custom solve
        useEffect(() => {
            //check change here
            const isEqual = arrayEquals(myArray, previousArray) && previousBoolean === myBoolean;
    
            if (!isEqual)
                handleEffect();
        });
    
        useEffect(() => {
            console.log('child-useEffect-call with sallow compare');
    
            if(myBoolean) {
                setMyString(myArray[0]);
            }
        }, [myBoolean, myArray]);
    
        return myString;
    }
    
    const Any = () => {
        const [array, setArray] = useState(['1','2','3']);
        console.log('parent-render');
    
        //array is always changed
        // useEffect(() => {
        //     setInterval(() => {
        //         setArray(['1','2', Math.random()]);
        //     }, 2000);
        // }, []);
    
    
        //be fine. ref is not changed.
        // useEffect(() => {
        //     setInterval(() => {
        //         setArray(array);
        //     }, 2000);
        // }, []);
    
    
        //changed ref but value in array are not changed -> handle this case
        useEffect(() => {
            setInterval(() => {
                setArray(['1','2', '3']);
            }, 2000);
        }, []);
    
        return <div> <MyComponent myBoolean={true} myArray={array}/> </div>;
    }
    

    【讨论】:

      【解决方案2】:

      解决方案 1

      如果你总是需要第一项,从数组中提取它,并将其用作依赖项:

      const MyComponent = ({ myBoolean, myArray }) => {
        const [myString, setMyString] = useState('');
      
        const item = myArray[0];
      
        useEffect(() => {
          if(myBoolean) {
            setMyString(item);
          }
        }, [myBoolean, item]);
      }
      

      解决方案 2

      如果您不想对myArray 的更改做出反应,请将其设置为useRef() 的引用:

      const MyComponent = ({ myBoolean, myArray }) => {
        const [myString, setMyString] = useState('');
        const arr = useRef(myArray);
      
        useEffect(() => { arr.current = myArray; }, [myArray]);
      
        useEffect(() => {
          if(myBoolean) {
            setMyString(arr.current);
          }
        }, [myBoolean]);
      }
      

      注意: redux 不应该在每次状态更新时生成新数组,除非数组或它的项目实际发生变化。如果选择器生成数组,请阅读记忆选择器(reselect 是一个很好的库)。

      【讨论】:

        猜你喜欢
        • 2022-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-09
        • 2020-04-29
        • 2021-10-11
        • 2021-09-29
        • 2022-10-14
        相关资源
        最近更新 更多