解密使用useMount和useUnmount的重要性

在使用 React 类组件时,React 提供了明显的生命周期方法,可以在特定的生命周期方法中处理特定的逻辑。然而,自从 React Hooks 推出以来,React 并没有明确推出相应的生命周期方法,而是更多地使用useEffect来模拟生命周期方法,例如useMount、useUnmount等等。
然而,在笔者长期使用 React Hooks 进行项目开发的过程中,发现不正确地使用useEffect来模拟生命周期方法可能会引发一些新的问题。
React Hooks 的执行顺序
下面是一份来自社区的 React Hooks 的执行顺序图:

原理分析
以一段简单的代码解释 React Hooks 的执行顺序:
import { useEffect, useMemo, useState, useLayoutEffect } from "react";
const Count = () => {
const [count, setCount] = useState(() => {
console.log(1);
return 0;
});
const double = useMemo(() => {
console.log(2);
return count * 2;
}, [count]);
const handleClick = () => setCount((c) => c + 1);
useEffect(() => {
console.log(4);
return () => {
console.log(6);
};
}, [count]);
useLayoutEffect(() => {
console.log(3);
return () => {
console.log(5);
};
}, [count]);
return (
<div>
<p>
{count}---{double}
</p>
<button onClick={handleClick}>click</button>
</div>
);
};
export default Count;
在浏览器中首次运行该代码,结果如下:

以 React update DOM and Refs 作为执行顺序的分界线,会先执行 useState、useMemo 、 useLayoutEffect 以及内部的变量或方法声明,后执行 useEffect。
点击 click 按钮,得到了一份新结果如下:

通过结果可以得到,先执行 useMemo,接着执行 useLayoutEffect 的 side effect cleanup,useEffect 的 side effect cleanup,等到 React update DOM and Refs 执行后,再执行 useLayoutEffect、useEffect。
通过这个例子,基本上弄清楚 useEffect 的执行顺序,由此分析使用 useEffect 模拟生命周期方法不当会导致什么问题。
- 对于生命周期挂载方法,使用
useEffect模拟mount如下:useEffect(() => { // do something }, []);只有当
useEffect的 deps 参数是空数组时,该用法才等同于mount方法 - 对于组件销毁的生命周期方法,使用
useEffect模拟unmount如下:useEffect(() => { return () => { // do something } }, []);
useMount 和 useUnmount
前面的问题根本原因是 useEffect 与 Lifecycle Methods 需要解耦。如果 useEffect 的 deps 参数不是空数组,那么当前的 useEffect 不等同 mount 方法,就会造成意外的结果
社区里提供专门的 ahooks 解决这个问题,这个第三方库中有两个重要方法,分别是 useMount 和 useUnmount
useMount 的实现如下:
// useMount.ts
import { useEffect } from 'react'
const useMount = (fn: () => void) => {
if (!isFunction(fn)) {
console.error(`useMount: parameter \`fn\` expected to be a function, but got "${typeof fn}".`)
}
useEffect(() => {
fn?.()
}, [])
}
export default useMount
useUnmount 的实现如下:
// useUnMount.ts
import { useEffect, useRef } from 'react'
export default function useUnmount(fn: () => void): void {
if (!isFunction(fn)) {
console.error(`useUnmount: parameter \`fn\` expected to be a function, but got "${typeof fn}".`)
}
const ref = useRef(fn)
useEffect(
(): (() => void) => (): void => {
ref.current?.()
},
[]
)
}
function isFunction(fn: unknown): fn is Function {
return typeof fn === 'function'
}
在项目中这样使用useMount和useUnMount:
const App = () => {
useMount(() => {
// ...
})
useUnMount(() => {
// ...
})
return <></>
}
使用useMount和useUnmount就不用考虑传入的依赖,实现useEffect与 Lifecycle Methods 解耦
以上就是关于我们为什么需要 useMount 和 useUnmount 的详细内容,更多请关注码云笔记其它相关文章!
以上关于解密使用useMount和useUnmount的重要性的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » 解密使用useMount和useUnmount的重要性

微信
支付宝