搜尋

首頁  >  問答  >  主體

將包含數組作為 useEffect 中的依賴項

每 5 秒就會有一些來自長輪詢的數據,我希望我的元件在每次數組的一項(或數組長度本身)發生變化時調度一個操作。 在將陣列作為依賴項傳遞給 useEffect 時,如何防止 useEffect 進入無限循環,但如果任何值發生變化,仍然設法調度一些操作?

useEffect(() => {
  console.log(outcomes)
}, [outcomes])

其中 outcomes 是一個 ID 數組,例如 [123, 234, 3212]。數組中的項目可能會被替換或刪除,因此數組的總長度可能(但不一定)保持不變,因此傳遞 outcomes.length 作為依賴項並非如此。

outcomes 來自 reselect 的自訂選擇器:

const getOutcomes = createSelector(
  someData,
  data => data.map(({ outcomeId }) => outcomeId)
)


#
P粉748218846P粉748218846393 天前555

全部回覆(2)我來回復

  • P粉464208937

    P粉4642089372023-10-18 15:49:11

    使用 JSON.stringify() 或任何深度比較方法可能效率較低,如果您事先知道物件的形狀,您可以編寫自己的效果鉤子來根據結果觸發回調您的自訂相等函數。

    useEffect 的工作原理是檢查相依性陣列中的每個值是否與前一渲染中的值相同,如果其中一個不是,則執行回呼。因此,我們只需要使用 useRef 保留我們感興趣的資料實例,並且僅在自訂相等性檢查返回 false 時指派一個新實例來觸發效果。

    function arrayEqual(a1: any[], a2: any[]) {
      if (a1.length !== a2.length) return false;
      for (let i = 0; i < a1.length; i++) {
        if (a1[i] !== a2[i]) {
          return false;
        }
      }
      return true;
    }
    
    type MaybeCleanUpFn = void | (() => void);
    
    function useNumberArrayEffect(cb: () => MaybeCleanUpFn, deps: number[]) {
      const ref = useRef(deps);
    
      if (!arrayEqual(deps, ref.current)) {
        ref.current = deps;
      }
    
      useEffect(cb, [ref.current]);
    }
    

    用法

    function Child({ arr }: { arr: number[] }) {
      useNumberArrayEffect(() => {
        console.log("run effect", JSON.stringify(arr));
      }, arr);
    
      return 
    {JSON.stringify(arr)}
    ; }

    更進一步,我們也可以透過建立一個接受自訂相等函數的效果鉤子來重複使用該鉤子。

    type MaybeCleanUpFn = void | (() => void);
    type EqualityFn = (a: DependencyList, b: DependencyList) => boolean;
    
    function useCustomEffect(
      cb: () => MaybeCleanUpFn,
      deps: DependencyList,
      equal?: EqualityFn
    ) {
      const ref = useRef(deps);
    
      if (!equal || !equal(deps, ref.current)) {
        ref.current = deps;
      }
    
      useEffect(cb, [ref.current]);
    }
    

    用法

    useCustomEffect(
      () => {
        console.log("run custom effect", JSON.stringify(arr));
      },
      [arr],
      (a, b) => arrayEqual(a[0], b[0])
    );
    

    現場演示

    回覆
    0
  • P粉662802882

    P粉6628028822023-10-18 12:32:21

    您可以傳遞 JSON.stringify(outcomes) 作為依賴項清單:

    了解更多此處

    #
    useEffect(() => {
      console.log(outcomes)
    }, [JSON.stringify(outcomes)])

    回覆
    0
  • 取消回覆