簡體   English   中英

如何處理useEffect依賴數組中不變的數組?

[英]How to handle an unchanging array in useEffect dependency array?

我有一個這樣的組件。 我想要的是 useEffect 函數在myBoolean更改時隨時運行。

我可以通過將依賴數組設置為[myBoolean]來實現這一點。 但是后來我收到一條警告,指出我違反了exhaustive-deps規則,因為我在函數內部引用了myArray 我不想違反該規則,因此我將依賴項數組設置為[myBoolean, myArray]

但后來我得到了一個無限循環。 發生的事情是每次myArray更改時都會觸發 useEffect ,這是每次更改,因為事實證明myArray來自 redux 並在每次重新渲染時重新生成。 即使數組的元素與之前的相同,React 也會使用===將數組與其之前的版本進行比較,並且它不是同一個對象,因此不相等。

那么這樣做的正確方法是什么? 如何僅在myBoolean更改時運行我的代碼,而不違反exhaustive-deps規則?

我已經看到了這個,但我仍然不確定在這種情況下的解決方案是什么。

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

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

解決方案1

如果您總是需要第 1 項,請從數組中提取它,並將其用作依賴項:

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

  const item = myArray[0];

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

解決方案2

如果您不想對myArray更改做出反應,請使用useRef()將其設置為 ref :

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是一個很好的庫)。

我有一個關於保存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>;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM