utu*_*rnr 28 reactjs react-hooks
使用React的新效果钩子,如果重新渲染之间某些值没有改变,我可以告诉React跳过应用效果 - 来自React的文档示例:
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes
Run Code Online (Sandbox Code Playgroud)
但是上面的例子应用了初始渲染时的效果,以及后续重新渲染的位置count.如何告诉React跳过初始渲染的效果?
Sco*_*ner 57
这是一个自定义钩子,它只提供一个布尔标志来指示当前渲染是否是第一个渲染(安装组件时)。它与其他一些答案大致相同,但您可以在 auseEffect或 render 函数或您想要的组件中的任何其他地方使用该标志。也许有人可以提出一个更好的名字。
import { useRef, useEffect } from 'react';
export const useIsMount = () => {
const isMountRef = useRef(true);
useEffect(() => {
isMountRef.current = false;
}, []);
return isMountRef.current;
};
Run Code Online (Sandbox Code Playgroud)
你可以像这样使用它:
import React, { useEffect } from 'react';
import { useIsMount } from './useIsMount';
const MyComponent = () => {
const isMount = useIsMount();
useEffect(() => {
if (isMount) {
console.log('First Render');
} else {
console.log('Subsequent Render');
}
});
return isMount ? <p>First Render</p> : <p>Subsequent Render</p>;
};
Run Code Online (Sandbox Code Playgroud)
如果您有兴趣,这里有一个测试:
import { renderHook } from '@testing-library/react-hooks';
import { useIsMount } from '../useIsMount';
describe('useIsMount', () => {
it('should be true on first render and false after', () => {
const { result, rerender } = renderHook(() => useIsMount());
expect(result.current).toEqual(true);
rerender();
expect(result.current).toEqual(false);
rerender();
expect(result.current).toEqual(false);
});
});
Run Code Online (Sandbox Code Playgroud)
我们的用例是隐藏动画元素,如果初始道具表明它们应该被隐藏。如果道具发生变化,在稍后的渲染中,我们确实希望元素具有动画效果。
Est*_*ask 52
正如指南所述,
Effect Hook,useEffect增加了从功能组件执行副作用的功能.它与React类中的componentDidMount,componentDidUpdate和componentWillUnmount具有相同的用途,但统一为单个API.
在本指南中的示例中,预期count仅在初始渲染时为0:
const [count, setCount] = useState(0);
Run Code Online (Sandbox Code Playgroud)
所以它会像componentDidUpdate额外的检查一样工作:
useEffect(() => {
if (count)
document.title = `You clicked ${count} times`;
}, [count]);
Run Code Online (Sandbox Code Playgroud)
这基本上是如何使用自定义钩子而不是useEffect可以工作:
function useDidUpdateEffect(fn, inputs) {
const didMountRef = useRef(false);
useEffect(() => {
if (didMountRef.current)
fn();
else
didMountRef.current = true;
}, inputs);
}
Run Code Online (Sandbox Code Playgroud)
积分转到@Tholle建议useRef代替setState.
Ven*_*sky 26
我找到了一个更简单的解决方案,不需要使用另一个钩子,但它有缺点。
useEffect(() => {
// skip initial render
return () => {
// do something with dependency
}
}, [dependency])
Run Code Online (Sandbox Code Playgroud)
这只是一个例子,如果您的案例非常简单,还有其他方法可以做到。
这样做的缺点是不能有清理效果,只有在依赖数组第二次改变时才会执行。
不建议使用此方法,您应该使用其他答案所说的内容,但我只在此处添加了此内容,以便人们知道这样做的方法不止一种。
只是为了更清楚,您不应该使用这种方法来解决问题中的问题(跳过初始渲染),这仅用于教学目的,表明您可以用不同的方式做同样的事情。如果您需要跳过初始渲染,请使用其他答案的方法。
一个 TypeScript 和 CRA 友好的钩子,用 替换它useEffect,这个钩子的工作原理类似,useEffect但不会在第一次渲染发生时被触发。
import * as React from 'react'
export const useLazyEffect:typeof React.useEffect = (cb, dep) => {
const initializeRef = React.useRef<boolean>(false)
React.useEffect((...args) => {
if (initializeRef.current) {
cb(...args)
} else {
initializeRef.current = true
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, dep)
}
Run Code Online (Sandbox Code Playgroud)
我使用常规状态变量而不是引用。
// Initializing didMount as false
const [didMount, setDidMount] = useState(false)
// Setting didMount to true upon mounting
useEffect(() => setDidMount(true), [])
// Now that we have a variable that tells us wether or not the component has
// mounted we can change the behavior of the other effect based on that
const [count, setCount] = useState(0)
useEffect(() => {
if (didMount) document.title = `You clicked ${count} times`
}, [count])
Run Code Online (Sandbox Code Playgroud)
我们可以像这样将didMount逻辑重构为自定义钩子。
function useDidMount() {
const [didMount, setDidMount] = useState(false)
useEffect(() => setDidMount(true), [])
return didMount
}
Run Code Online (Sandbox Code Playgroud)
最后,我们可以像这样在组件中使用它。
const didMount = useDidMount()
const [count, setCount] = useState(0)
useEffect(() => {
if (didMount) document.title = `You clicked ${count} times`
}, [count])
Run Code Online (Sandbox Code Playgroud)
这是我的实现,基于 Estus Flask用 Typescript 编写的答案。它还支持清理回调。
import { DependencyList, EffectCallback, useEffect, useRef } from 'react';
export function useDidUpdateEffect(
effect: EffectCallback,
deps?: DependencyList
) {
// a flag to check if the component did mount (first render's passed)
// it's unrelated to the rendering process so we don't useState here
const didMountRef = useRef(false);
// effect callback runs when the dependency array changes, it also runs
// after the component mounted for the first time.
useEffect(() => {
// if so, mark the component as mounted and skip the first effect call
if (!didMountRef.current) {
didMountRef.current = true;
} else {
// subsequent useEffect callback invocations will execute the effect as normal
return effect();
}
}, deps);
}
Run Code Online (Sandbox Code Playgroud)
useEffect下面的现场演示演示了 hooks和useDidUpdateEffecthooks之间的区别
| 归档时间: |
|
| 查看次数: |
13983 次 |
| 最近记录: |