尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

react-use useMount Hook 完全指南:组件挂载时执行一次回调的实现原理与实战用法

react-use useMount Hook 完全指南:组件挂载时执行一次回调的实现原理与实战用法 react-use useMount Hook 完全指南组件挂载时执行一次回调的实现原理与实战用法【免费下载链接】react-useReact Hooks — 项目地址: https://gitcode.com/gh_mirrors/re/react-use导读useMount是 react-use 生命周期Lifecycle系列中最常用的 Hook 之一它解决的是一个非常具体的问题在 React 函数组件挂载完成后只执行一次指定回调函数。本文将以 docs/useMount.md 为核心结合 src/useMount.ts 的源码实现、tests/useMount.test.ts 的测试用例以及同系列的useEffectOnce、useLifecycles讲清楚它的用法、源码原理、测试保障和适用边界让你读完即可在真实项目中安全使用。useMount 是什么按照官方文档的定义React lifecycle hook that calls a function after the component is mounted.useMount是一个 React 生命周期 Hook它会在组件挂载mount之后调用你传入的函数。如果你同时需要挂载和卸载两个阶段的回调官方建议改用useLifecycles详见 docs/useLifecycles.md。它的定位非常纯粹把组件挂载时做一次初始化这类逻辑封装成一行调用替代手写useEffect(fn, [])的样板代码也让代码语义一目了然——读者看到useMount立刻就能理解这段逻辑只在挂载时跑一次。快速上手基础用法文档给出的最小示例完整照搬自 docs/useMount.mdimport {useMount} from react-use; const Demo () { useMount(() alert(MOUNTED)); return null; };要点解读useMount直接从react-use包导入无需额外安装其他依赖它由包内导出见 src/index.ts 的export { default as useMount } from ./useMount;回调函数会在组件完成首次挂载后被调用这里的alert(MOUNTED)会在组件挂载后弹出一次组件渲染返回null不影响 Hook 的执行说明useMount只关心挂载时机与渲染内容无关。一个更贴近真实业务的例子组件挂载时拉取一次初始化数据、注册全局事件监听器或上报埋点。import {useMount} from react-use; const AnalyticsReporter ({pageName}) { useMount(() { trackPageView(pageName); // 页面挂载时上报一次访问 }); return div{pageName}/div; };API 签名文档中的类型签名如下useMount(fn: () void);参数说明参数类型必填说明fn() void是组件挂载后要执行的回调函数无返回值要求值得注意的约束fn的类型是() void这意味着你不需要也不应该返回清理函数——卸载时的清理工作不在useMount的职责范围内。若需要在卸载时执行清理逻辑应使用useLifecycles(mount, unmount)或在普通useEffect中返回清理函数回调只执行一次组件后续的多次重渲染rerender不会再次触发它。源码实现三个 Hook 的递进关系1. useMount薄封装src/useMount.ts 的完整实现只有 7 行import useEffectOnce from ./useEffectOnce; const useMount (fn: () void) { useEffectOnce(() { fn(); }); }; export default useMount;可以看到useMount本身不做任何复杂逻辑只是把fn包装进useEffectOnce的回调中。2. useEffectOnce真正的只执行一次来源src/useEffectOnce.ts 的实现是import { EffectCallback, useEffect } from react; const useEffectOnce (effect: EffectCallback) { useEffect(effect, []); }; export default useEffectOnce;它本质上就是useEffect(effect, [])的别名封装——空依赖数组[]保证了 effect 只在组件首次挂载后执行一次这正是useMount只执行一次语义的底层来源。useEffectOnce对应的文档见 docs/useEffectOnce.md。需要理解的是useMount(fn)等价于useEffect(() { fn(); }, [])但前者把意图表达得更明确也避免了开发者手写依赖数组时可能出现的错误例如误填依赖导致重复执行。3. useLifecycles挂载 卸载的完整方案文档明确提示UseuseLifecyclesif you need both a mount and unmount function。看 src/useLifecycles.ts 的实现import { useEffect } from react; const useLifecycles (mount, unmount?) { useEffect(() { if (mount) { mount(); } return () { if (unmount) { unmount(); } }; }, []); }; export default useLifecycles;它同样基于空依赖数组的useEffect但借助 React effect 的清理函数cleanup机制在组件卸载时执行unmount回调。因此只需要挂载逻辑 → 用useMount(fn)挂载和卸载逻辑都要 → 用useLifecycles(mount, unmount)。从源码结构看useMount是useLifecycles的降级版本——useLifecycles未传unmount参数时行为上几乎等同于useMount但useMount的语义更聚焦阅读成本更低。测试保障挂载、卸载与重渲染三个场景tests/useMount.test.ts 用testing-library/react-hooks的renderHook编写了三个测试用例完整定义了useMount的契约行为import { renderHook } from testing-library/react-hooks; import { useMount } from ../src; const mockCallback jest.fn(); afterEach(() { jest.resetAllMocks(); }); it(should call provided callback on mount, () { renderHook(() useMount(mockCallback)); expect(mockCallback).toHaveBeenCalledTimes(1); }); it(should not call provided callback on unmount, () { const { unmount } renderHook(() useMount(mockCallback)); expect(mockCallback).toHaveBeenCalledTimes(1); unmount(); expect(mockCallback).toHaveBeenCalledTimes(1); }); it(should not call provided callback on rerender, () { const { rerender } renderHook(() useMount(mockCallback)); expect(mockCallback).toHaveBeenCalledTimes(1); rerender(); expect(mockCallback).toHaveBeenCalledTimes(1); });三个用例分别验证了挂载时调用一次renderHook挂载组件后回调恰好被调用 1 次卸载时不调用unmount()之后回调次数仍为 1证明useMount不会在卸载阶段执行任何逻辑这正是它与useLifecycles的差异点重渲染时不调用rerender()之后回调次数仍为 1证明空依赖数组的只执行一次语义稳定生效。这套测试直接反映了文档承诺的行为也是你使用该 Hook 时可以信赖的行为契约。深入理解几个关键实现细节空依赖数组与 effect 时序useEffect的空依赖数组意味着 effect 在浏览器绘制paint之后、组件完成首次提交时执行。因此useMount中的回调严格来说发生在挂载后的 effect 阶段而不是渲染阶段。如果你的回调需要读取 DOM此时 DOM 已经可用但如果回调会触发同步状态更新请留意这会导致一次额外的重渲染。与 React StrictMode 的关系useMount依赖useEffect的空依赖只执行一次语义。需要注意的是在 React 18 及以上版本开启StrictMode的开发环境下React 会刻意对 effect 进行挂载 → 卸载 → 再挂载的模拟以暴露不安全的副作用。因此在这种场景下useMount的回调可能会被调用两次这是 React 官方设计的行为并非 Hook 的缺陷生产构建不受影响。本仓库当前以 React 17 作为开发依赖见 package.json 的devDependencies但在更高版本 React 中使用时请留意这一差异。依赖闭包问题由于依赖数组为空useMount回调内捕获的是首次渲染时的闭包。如果回调内部读取了 props 或 state它拿到的是首次渲染的值后续更新不会反映到回调中。若你的初始化逻辑依赖最新状态应改用带依赖的普通useEffect而不是useMount。回调中不要返回清理函数useMount的参数类型是() void即使你在回调里返回了一个函数它也不会被 React 当作 cleanup 执行——useMount的包装层没有把它透传给useEffect的清理机制对比useEffectOnce的EffectCallback类型会透传返回值。需要卸载清理时请显式使用useLifecycles或原生useEffect。在 react-use 生命周期体系中的位置react-use 的 docs/Lifecycles.md 对生命周期类 Hook 的定义是Lifecycle Hooks modify and extend built-in React hooks or imitate React Class component lifecycle patterns.useMount正是这类 Hook 的代表它把 React Class 组件中componentDidMount的语义以函数组件 Hook 的形式复刻出来。与它配套的生命周期 Hook 还有useMount挂载时执行一次useLifecycles挂载 卸载回调useUnmount卸载时执行对应 docs/useUnmount.mduseMountedState返回一个判断组件是否仍处于挂载状态的函数见 src/useMountedState.ts常用于异步回调中防止卸载后更新状态。按需组合这些 Hook即可在函数组件中完整复刻 Class 组件的生命周期管理能力。常见使用场景一次性初始化组件挂载时执行一次性的数据拉取、订阅或计算第三方库初始化在挂载后初始化图表、地图等需要 DOM 就绪的库埋点上报页面/组件级的一次性曝光上报全局事件注册配合useLifecycles在挂载时注册、卸载时移除全局事件监听。小结useMount是 react-use 中实现最简洁、语义最清晰的 Hook 之一7 行源码、一个空依赖数组、三个测试用例就完整定义了组件挂载后执行一次回调的行为契约。理解它你也就同时理解了useEffectOnce与useLifecycles的底层实现掌握了 react-use 生命周期 Hook 家族的核心设计模式。当你在项目中需要只执行一次的初始化逻辑时useMount是一个比手写useEffect(fn, [])更直观、更不易出错的选择。【免费下载链接】react-useReact Hooks — 项目地址: https://gitcode.com/gh_mirrors/re/react-use创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表