reactjs 自定义useAsyncEffect中的依赖项溢出,如何使其在deps更新时运行一次?

4xy9mtcn  于 2023-05-17  发布在  React
关注(0)|答案(1)|浏览(101)

因此,我创建了一个useAsyncHook来查询常规API,但是,我注意到我有一个依赖性问题,因为如果依赖项是空数组,浏览器将溢出。
我尝试了一些事情,比如以不同的方式管理这些依赖关系,我创建了一个简单的沙箱来展示一个简单的例子。
我就是这样消费的。

import useAsyncEffect from "./useAsyncEffect";

const useSomethingExample = ({ processes, datasets }) => {
  console.log(processes);
  console.log(datasets);

  return useAsyncEffect(async () => {
    await new Promise((resolve) => {
      setTimeout(() => {
        resolve({ processes, datasets });
      }, 300);
    });
  }, [processes, datasets]);
};

export default useSomethingExample;

您必须将App.tsx中的第6行和第7行更改为空数组而不是null才能看到问题。
[sanbox示例] https://codesandbox.io/s/react-typescript-forked-gd510i?file=/src/useAsyncEffect.ts

vmdwslir

vmdwslir1#

[depsArray]中的依赖项通过引用比较非原始对象(string,number,boolean)。在javascript中,[] ===[] => false。因此,在每次使用此钩子重新渲染组件时,都会创建新的空数组并将其传递给钩子,并且由于它们每次都有不同的引用- useEffect被触发,更新数据,导致调用组件的重新渲染结束等。
您可以首先为这些数组使用状态变量。

export default function App() {
  const [processes, setProcesses] = useState([]);
  const [datasets, setDatasets] = useState([]);

  const { result } = useSomethingExample({
    processes: processes,
    datasets: datasets
  });

  console.log("result");
  console.log(result);

  return (
    <div className="App">
      useAsyncEffect fails if processes are [] or datasets are []
    </div>
  );
}

如果你真的想让它看起来更漂亮,你可以通过添加一个内部状态来修改你的useSomethingExample。其中的useEffect使用lodash isEqual方法执行functional state updates,因此如果数组相等-则返回旧数组(Curr),旧引用,因此不会重新执行主useEffect。你可以使用你的比较实现,lodash不是强制性的。

import { useEffect, useState } from "react";
import _ from "lodash";
import useAsyncEffect from "./useAsyncEffect";

const useSomethingExample = ({ processes, datasets }) => {
  const [p, setP] = useState(processes);
  const [d, setD] = useState(datasets);

  useEffect(() => {
    setP((curr) => {
      if (_.isEqual(curr, processes)) return curr;
      return processes;
    });
  }, [processes]);

  useEffect(() => {
    setD((curr) => {
      if (_.isEqual(curr, datasets)) return curr;
      return datasets;
    });
  }, [datasets]);

  console.log(processes);
  console.log(datasets);

  return useAsyncEffect(async () => {
    await new Promise((resolve) => {
      setTimeout(() => {
        resolve({ processes: p, datasets: d });
      }, 300);
    });
  }, [p, d]);
};

export default useSomethingExample;

相关问题