将数组传递给 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)
)

原文由 user0101 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 593
2 个回答

您可以传递 JSON.stringify(outcomes) 作为依赖列表:

在这里 阅读更多

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

原文由 Loi Nguyen Huynh 发布,翻译遵循 CC BY-SA 4.0 许可协议

使用 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<number[]>(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 <pre>{JSON.stringify(arr)}</pre>;
}

更进一步,我们还可以通过创建一个接受自定义相等函数的效果挂钩来重用挂钩。

 type MaybeCleanUpFn = void | (() => void);
type EqualityFn = (a: DependencyList, b: DependencyList) => boolean;

function useCustomEffect(
  cb: () => MaybeCleanUpFn,
  deps: DependencyList,
  equal?: EqualityFn
) {
  const ref = useRef<DependencyList>(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])
);

现场演示

编辑 59467758/passing-array-to-useeffect-dependency-list

原文由 NearHuscarl 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进