use*_*101 27 reactjs react-hooks
有一些数据来自每 5 秒的长轮询,我希望我的组件在每次数组的一项(或数组长度本身)发生变化时分派一个动作。在将数组作为依赖项传递给 useEffect 时,如何防止 useEffect 进入无限循环,但如果任何值发生更改,仍然设法调度某些操作?
useEffect(() => {
console.log(outcomes)
}, [outcomes])
Run Code Online (Sandbox Code Playgroud)
其中outcomes是一组 ID,例如[123, 234, 3212]. 数组中的项目可能会被替换或删除,因此数组的总长度可能 - 但不必 - 保持不变,因此outcomes.length作为依赖传递不是这种情况。
outcomes 来自 reselect 的自定义选择器:
const getOutcomes = createSelector(
someData,
data => data.map(({ outcomeId }) => outcomeId)
)
Run Code Online (Sandbox Code Playgroud)
Huỳ*_*yễn 53
您可以JSON.stringify(outcomes)作为依赖项列表传递:
在这里阅读更多
useEffect(() => {
console.log(outcomes)
}, [JSON.stringify(outcomes)])
Run Code Online (Sandbox Code Playgroud)
Nea*_*arl 19
使用JSON.stringify()或 任何深度比较方法可能效率低下,如果您提前知道对象的形状,您可以编写自己的效果钩子,根据自定义相等函数的结果触发回调。
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]);
}
Run Code Online (Sandbox Code Playgroud)
function Child({ arr }: { arr: number[] }) {
useNumberArrayEffect(() => {
console.log("run effect", JSON.stringify(arr));
}, arr);
return <pre>{JSON.stringify(arr)}</pre>;
}
Run Code Online (Sandbox Code Playgroud)
更进一步,我们还可以通过创建一个接受自定义相等函数的效果钩子来重用该钩子。
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]);
}
Run Code Online (Sandbox Code Playgroud)
useCustomEffect(
() => {
console.log("run custom effect", JSON.stringify(arr));
},
[arr],
(a, b) => arrayEqual(a[0], b[0])
);
Run Code Online (Sandbox Code Playgroud)
另一个 ES6 选项是使用模板文字使其成为字符串。类似于JSON.stringify(),除了结果不会被包裹在[]
useEffect(() => {
console.log(outcomes)
}, [`${outcomes}`])
Run Code Online (Sandbox Code Playgroud)
另一种选择是,如果数组大小不变,则将其分布在:
useEffect(() => {
console.log(outcomes)
}, [ ...outcomes ])
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
21268 次 |
| 最近记录: |