通过结果可以得到,先执行 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 的详细内容,更多请关注www.mimiwuqi.com的其它相关文章!