当前位置: 首页 > 知识库问答 >
问题:

当所有依赖项都更改时使用效果?

杜翰林
2023-03-14

当前,只有一个依赖项发生更改时,才会触发useffect

当两个(或所有)依赖项都已更改时,我如何更新/使用它进行回击?

共有3个答案

皮承基
2023-03-14

我喜欢@AustinBrunkhorst的soultion,但是你可以用更少的代码来完成它。

使用仅在满足条件时更新的状态对象,并将其设置在第二个useEffect中。

import React, { useEffect, useState } from "react";
import "./styles.css";

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

  useEffect(() => {
    setAB(prev => {
      console.log('prev AB', prev)
      return (a !== prev.a && b !== prev.b) 
        ? {a,b} 
        : prev;  // do nothing
    })
  }, [a, b])

  useEffect(() => {
    console.log('both have changed')
  }, [ab])

  return (
    <div className="App">
      <div>Click on a button to increment its value.</div>
      <button onClick={() => setA((prev) => prev + 1)}>A: {a}</button>
      <button onClick={() => setB((prev) => prev + 1)}>B: {b}</button>
    </div>
  );
}
周弘盛
2023-03-14

您必须跟踪依赖项以前的值,并检查它们中是否只有一个发生了更改,或者两个/全部都发生了更改。基本实现可以如下所示:

import React from "react";

const usePrev = value => {
  const ref = React.useRef();

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

  return ref.current;
};

const App = () => {
  const [foo, setFoo] = React.useState(0);
  const [bar, setBar] = React.useState(0);
  const prevFoo = usePrev(foo);
  const prevBar = usePrev(bar);

  React.useEffect(() => {
    if (prevFoo !== foo && prevBar !== bar) {
      console.log("both foo and bar changed!");
    }
  }, [prevFoo, prevBar, foo, bar]);

  return (
    <div className="App">
      <h2>foo: {foo}</h2>
      <h2>bar: {bar}</h2>
      <button onClick={() => setFoo(v => v + 1)}>Increment foo</button>
      <button onClick={() => setBar(v => v + 1)}>Increment bar</button>
      <button
        onClick={() => {
          setFoo(v => v + 1);
          setBar(v => v + 1);
        }}
      >
        Increment both
      </button>
    </div>
  );
};

export default App;

这里还有一个代码沙盒链接供您使用。

您可以在其他地方检查usePrev钩子是如何工作的,例如这里。

赖明煦
2023-03-14

当所有依赖项都已更改时,需要添加一些逻辑来调用效果。这里的useeffectAllDepsChange应该实现您期望的行为。

这里的策略是将以前的DEP与当前的DEP进行比较。如果它们没有完全不同,我们会将以前的dep保存在ref中,直到它们完全不同才进行更新。这允许您在调用效果之前多次更改DEP。

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

受Richard启发的另一种方法更干净,但缺点是在更新过程中渲染更多。

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);
}
 类似资料:
  • 我有一个React组件,它使用钩子获取数据,如下所示: 每次或更改时,都会运行钩子。但是,我也在本地缓存数据,并且只希望在和都更改时运行效果(因为对于每个键/选项组合,数据总是相同的)。 是否有一种干净的方法来依赖于和的组合,而不是使用React钩子的或?

  • 在Synfony 3.3中,DI的新最佳实践 是使用普通构造函数依赖项注入(或控制器中的“操作”注入),而不是通过$this获取公共服务- 如官方留档所见 因此,无需指定服务,因为我们可以在类控制器中键入提示: 这似乎工作得很好,但如果我扩展了一个类并在构造函数中添加了更多参数呢??? 现在我得到一个循环引用错误: [Symfony\Component\DependencyInjection\Ex

  • 我正试图让maven下载所有的依赖项(编译、测试、插件等)。)这样我就可以避免让我们的dockerized构建浪费不必要的时间一遍又一遍地下载它们。 我们已经对maven build进行了dockerized,这样我们就可以从jenkins运行它,而无需在jenkins机器上安装大量构建特定的依赖项(Java、redis、maven依赖项等)。我们的构建依赖于增量docker构建,它只执行实际需要

  • Java和Maven新手。 我试图配置我的应用程序,以便我可以通过cmd线生成一个jar,其中包含我所有的依赖项。 据我所知,我正在正确设置Pom以使用此插件:https://github.com/javafx-maven-plugin/javafx-maven-plugin 以下是我在Pom中的依赖项: 在我的

  • 在我的单元测试中,无法识别PowerMockRunner,尽管我的pom中有我需要的所有依赖项,并且下载了所有必需的jar。我正在尝试测试静态方法。我一直收到错误

  • 我是maven的新手。(我已经搜索了几个小时的答案,但没有运气。mvn依赖:复制依赖不能解决我的问题)我需要复制项目的所有依赖项(以jar的形式),如果我的一个jar依赖于另一个工件,也复制该工件。 示例project1 pom。xml: “project1”依赖于project2。人工制品罐子当我使用“mvn依赖项:复制依赖项”时,我得到了project2。人工制品但我没有得到project3。