背景
本文是手写hooks系列第三期,该篇难度:⭐️。
由于React中的useEffect机制,不管什么场景下,useEffect都会在初次渲染期间执行。那么如何实现class组件中的componentDidUpdate
呢?
今天带着大家实现一个函数式组件版本的componentDidUpdate
。
需求
现在要求实现自定义hook:useUpdateEffect
,实现后具体用法与useEffect
相同,效果与componentDidUpdate
相同。
const Test = () => {
const [num, setNum] = useState(0);
useUpdateEffect(() => {
console.log(num, "更新后的num");
}, [num]);
return (
<div>
{num}
<button onClick={() => setNum(num + 1)}>add</button>
</div>
);
};
复制代码
编码实现
第一步:先定义好输入输出结构。
export const useUpdateEffect: typeof useEffect = (effect, deps) => {
useEffect(() => {
return effect();
}, deps);
};
复制代码
第二步:对初次渲染进行处理,这里的核心是判断初次渲染的时机,如果是初次渲染则不执行传入的effect函数
。
这里可以通过useRef
的方式来判断是否是第一次渲染。
export const useUpdateEffect: typeof useEffect = (effect, deps) => {
const ref = useRef(true);
useEffect(() => {
if (ref.current) {
ref.current = false; //如果是初次渲染则设置为false
} else {
return effect(); //再次渲染时再执行
}
}, deps);
};
复制代码
第三步:代码优化。这里其实我们可以把是否是第一次渲染的逻辑,单独提取成一个公共hook:useFirstMountState
,这样代码逻辑更清晰。
export function useFirstMountState(): boolean {
const isFirst = useRef(true);
if (isFirst.current) {
isFirst.current = false;
return true;
}
return isFirst.current;
}
复制代码
优化后的useUpdateEffect
:
export const useUpdateEffect: typeof useEffect = (effect, deps) => {
const isFirstMount = useFirstMountState(); //是否是第一次渲染
useEffect(() => {
if (!isFirstMount) {
return effect();
}
}, deps);
};
复制代码
总结
本文涉及到的所有代码均放在github上的 Demo 中,觉得不错点个赞,嘻嘻❤️❤️❤️。
欢迎大家在评论区留言,给出更优秀的实践!