当所有依赖项都改变时,useEffect吗?

时间:2020-07-18 23:23:36

标签: reactjs react-hooks

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

当两个(或全部)依赖项都发生更改时,如何更新/使用它来回发?

4 个答案:

答案 0 :(得分:7)

您需要添加一些逻辑以在所有依赖项都更改后调用效果。这是useEffectAllDepsChange,应该可以实现您想要的行为。

此处的策略是将以前的深度与当前的深度进行比较。如果它们没有什么不同,我们会将以前的部门保留在ref中,直到它们更新为止。这样,您可以在调用效果之前多次更改deps。

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

Edit vibrant-sky-q9hju

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

答案 1 :(得分:3)

我喜欢@AustinBrunkhorst的灵魂,但是您可以用更少的代码来做到这一点。

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

    private DateTime _startTime;
    public DateTime StartTime {
        get => _startTime;
        set => _startTime = new DateTime(value.Ticks, DateTimeKind.Utc);
    }

Edit relaxed-https-w5grz

答案 2 :(得分:2)

您必须跟踪依赖项的先前值,并检查是否仅更改了其中之一,或者同时更改了两者/全部。基本实现如下所示:

usePrev

这里也是一个CodeSandbox link可以玩耍的地方。

您可以检查import numpy as np import pandas as pd import scipy as sp import import matplotlib.pyplot as plt import csv source=open("C:\DATA ANALYSIS OPTIMIZATION\TrumpForbesRichestAmericans.csv") data = np.genfromtxt(source, dtype=None, delimiter=",", skip_header=1) print(data.head(5)) print(data.rank.describe()) print(data) 钩子如何在其他地方(例如here)工作。

答案 3 :(得分:0)

为演示如何以各种方式组成钩子,这是我的方法。此选项不会在初始归因中调用效果。

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

function usePrevious(state) {
  const ref = useRef();

  useEffect(() => {
    ref.current = state;
  });

  return ref.current;
}

function useAllChanged(callback, array) {
  const previousArray = usePrevious(array);

  console.log("useAllChanged", array, previousArray);

  if (previousArray === undefined) return;

  const allChanged = array.every((state, index) => {
    const previous = previousArray[index];
    return previous !== state;
  });

  if (allChanged) {
    callback(array, previousArray);
  }
}

const randomIncrement = () => Math.floor(Math.random() * 4);

export default function App() {
  const [state1, setState1] = useState(0);
  const [state2, setState2] = useState(0);
  const [state3, setState3] = useState(0);

  useAllChanged(
    (state, prev) => {
      alert("Everything changed!");
      console.info(state, prev);
    },
    [state1, state2, state3]
  );

  const onClick = () => {
    console.info("onClick");
    setState1(state => state + randomIncrement());
    setState2(state => state + randomIncrement());
    setState3(state => state + randomIncrement());
  };

  return (
    <div className="App">
      <p>State 1: {state1}</p>
      <p>State 2: {state2}</p>
      <p>State 3: {state3}</p>

      <button onClick={onClick}>Randomly increment</button>
    </div>
  );
}

Edit dazzling-swartz-e3oq6