将数组传递给useEffect依赖项列表

时间:2019-12-24 10:58:27

标签: reactjs react-hooks

每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)
)

5 个答案:

答案 0 :(得分:5)

另一个 ES6 选项是使用 template literals 使其成为字符串。与 JSON.stringify() 类似,但结果不会包含在 []

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

另一种选择,如果数组大小没有改变,将spread放入:

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

答案 1 :(得分:1)

使用 JSON.stringify() 或任何深度比较方法可能效率低下,如果您提前知道对象的形状,您可以编写自己的效果钩子,根据您自定义的相等函数的结果触发回调。< /p>

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])
);

现场演示

Edit 59467758/passing-array-to-useeffect-dependency-list

答案 2 :(得分:0)

React Hooks概念-将空数组作为第二个参数传递给 useEffect 使其仅在安装和卸载时运行,从而停止了无限循环。

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

供您参考react-hooks

答案 3 :(得分:0)

您可以通过JSON.stringify(outcomes)作为依赖项列表:

了解更多here

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

答案 4 :(得分:0)

您需要为数组使用状态,因为如果您不使用setOutcomes更改数组,则useEffect不会触发,例如results.push(1)将不起作用:

const [outcomes, setOutcomes] = useState([1,2])

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

function doFn(){
   setOutcomes([1,1])
}