只有一个依赖项发生更改时,会触发当前useEffect
。
当两个(或全部)依赖项都发生更改时,如何更新/使用它来回发?
答案 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>
);
}
受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);
}
答案 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>
);
}