当所有依赖项都改变时使用效果? [英] useEffect when all dependencies have changed?

查看:18
本文介绍了当所有依赖项都改变时使用效果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当前 useEffect 仅在依赖项之一发生更改时触发.

当两个(或所有)依赖项都发生变化时,我如何更新/使用它来回火?

解决方案

当所有依赖项都发生变化时,您需要添加一些逻辑来调用您的效果.这是应该实现您想要的行为的 useEffectAllDepsChange.

这里的策略是将之前的 deps 与当前的 deps 进行比较.如果它们不是全部不同,我们将之前的 deps 保留在 ref 中,并且在它们不同之前不要更新它.这允许您在调用效果之前多次更改 deps.

import React, { useEffect, useState, useRef } from "react";//取自 https://usehooks.com/usePrevious/函数usePrevious(值){const ref = useRef();useEffect(() => {ref.current = 值;}, [价值]);返回 ref.current;}函数 useEffectAllDepsChange(fn, deps) {const prevDeps = usePrevious(deps);const changeTarget = useRef();useEffect(() => {//没有什么可比较的if (changeTarget.current === undefined) {changeTarget.current = prevDeps;}//我们正在挂载,所以调用回调if (changeTarget.current === undefined) {返回 fn();}//确保每个依赖项都已更改if (changeTarget.current.every((dep, i) => dep !== deps[i])) {changeTarget.current = deps;返回 fn();}}, [fn, prevDeps, deps]);}导出默认函数 App() {const [a, setA] = useState(0);const [b, setB] = useState(0);useEffectAllDepsChange(() => {console.log(运行效果", [a, b]);}, [a, b]);返回 (<div><button onClick={() =>setA((prev) => prev + 1)}>A: {a}</button><button onClick={() =>setB((prev) => prev + 1)}> B: {b}</button>

);}

受 Richard 启发的另一种方法更简洁,但缺点是更新时渲染次数更多.

function useEffectAllDepsChange(fn, deps) {const [changeTarget, setChangeTarget] = useState(deps);useEffect(() => {setChangeTarget(prev => {if (prev.every((dep, i) => dep !== deps[i])) {退货部门;}返回上一个;});}, [deps]);useEffect(fn, changeTarget);}

Currently useEffect is fired when just one of the dependencies have changed.

How could I update it / use it to fire back when both ( or all ) of the dependencies have changed?

解决方案

You'll need to add some logic to call your effect when all dependencies have changed. Here's useEffectAllDepsChange that should achieve your desired behavior.

The strategy here is to compare the previous deps with the current. If they aren't all different, we keep the previous deps in a ref an don't update it until they are. This allows you to change the deps multiple times before the the effect is called.

import React, { useEffect, useState, useRef } from "react";

// taken from https://usehooks.com/usePrevious/
function usePrevious(value) {
  const ref = useRef();

  useEffect(() => {
    ref.current = value;
  }, [value]);
  
  return ref.current;
}

function useEffectAllDepsChange(fn, deps) {
  const prevDeps = usePrevious(deps);
  const changeTarget = useRef();

  useEffect(() => {
    // nothing to compare to yet
    if (changeTarget.current === undefined) {
      changeTarget.current = prevDeps;
    }

    // we're mounting, so call the callback
    if (changeTarget.current === undefined) {
      return fn();
    }

    // make sure every dependency has changed
    if (changeTarget.current.every((dep, i) => dep !== deps[i])) {
      changeTarget.current = deps;

      return fn();
    }
  }, [fn, prevDeps, deps]);
}

export default function App() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);

  useEffectAllDepsChange(() => {
    console.log("running effect", [a, b]);
  }, [a, b]);

  return (
    <div>
      <button onClick={() => setA((prev) => prev + 1)}>A: {a}</button>
      <button onClick={() => setB((prev) => prev + 1)}>B: {b}</button>
    </div>
  );
}

An alternate approach inspired by Richard is cleaner, but with the downside of more renders across updates.

function useEffectAllDepsChange(fn, deps) {
  const [changeTarget, setChangeTarget] = useState(deps);

  useEffect(() => {
    setChangeTarget(prev => {
      if (prev.every((dep, i) => dep !== deps[i])) {
        return deps;
      }

      return prev;
    });
  }, [deps]);

  useEffect(fn, changeTarget);
}

这篇关于当所有依赖项都改变时使用效果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆