创见博客
react-track-hooks:一个轻量可靠的 React 埋点 Hooks 库
七崽爱吃小饼干2026/07/14阅读 3专栏 react-track-hooks/React

react-track-hooks:一个轻量可靠的 React 埋点 Hooks 库

在前端应用中,埋点往往是产品分析、用户行为洞察和业务增长的基础能力。但在实际开发里,埋点代码很容易散落在点击事件、页面生命周期、曝光监听、表单提交等各种位置,既影响业务代码可读性,也增加了漏报、重复上报和失败丢失的风险。

react-track-hooks 正是为了解决这个问题而设计的。它是一个面向 React 项目的轻量埋点 Hooks 库,将点击、曝光、页面停留、首次渲染和自定义事件等常见场景封装成可复用 Hook,并内置批量上报、失败缓存和自动重试机制,让业务组件可以用更低成本接入稳定的埋点能力。

项目定位

react-track-hooks 的定位不是一个复杂的数据分析平台,而是一个专注于前端埋点采集层的 SDK。它不关心后端如何存储和分析数据,而是聚焦在浏览器侧如何更可靠、更优雅地采集行为事件,并把事件发送到指定接口。

这个定位让它非常适合 React 和 Next.js 项目使用。开发者只需要在项目入口配置一次全局上报地址和策略,然后在组件中使用对应 Hook,就可以完成常见埋点场景的接入。

核心能力

react-track-hooks 提供了几类最常见的埋点能力。

第一类是点击埋点。useTrackClick 会返回一个点击处理函数,业务组件可以直接绑定到按钮、卡片或任意可点击元素上。触发时,它会自动补充点击坐标,并携带自定义业务参数一起上报。

第二类是曝光埋点。useTrackExposure 基于浏览器的 IntersectionObserver 实现,返回一个 DOM ref。组件只需要把 ref 绑定到目标元素,元素达到指定可见比例后就会触发曝光事件。它支持配置曝光阈值,也支持只曝光一次,适合卡片、广告位、推荐内容等场景。

第三类是页面停留时长埋点。useTrackPageStay 会监听页面显隐、用户活跃行为和组件卸载,统计真实有效的活跃停留时间。它可以过滤过短停留,也能限制最长单次时长,避免异常数据污染分析结果。

第四类是组件首次渲染埋点。useTrackFirstRender 会在组件首次挂载后触发一次事件,适合记录关键组件是否被加载、首屏模块是否出现等场景。

第五类是自定义埋点。useTrackCustom 返回一个手动触发方法,适合表单提交、业务状态变化、流程节点完成等无法直接归类为点击或曝光的事件。

使用方式

项目入口处可以通过 useTrackInit 或手动调用配置函数完成初始化。全局配置包括单条上报地址、批量上报地址、是否启用埋点、是否启用批量上报、失败重试策略、批量队列策略、曝光策略和页面停留策略。

示例配置如下:

tsx
import { useTrackInit } from 'react-track-hooks';

function TrackProvider() {
  useTrackInit({
    trackUrl: '/api/track',
    batchTrackUrl: '/api/track/batch',
    enable: true,
    enableBatch: true,
    retryConfig: {
      maxRetryTimes: 3,
      initialDelay: 1000,
      delayMultiplier: 2,
    },
    batchConfig: {
      batchSize: 10,
      batchInterval: 5000,
    },
    exposureConfig: {
      exposureOnce: true,
      exposureThreshold: 0.5,
    },
    pageStayConfig: {
      timeout: 30 * 60 * 1000,
      minDuration: 2000,
      maxDuration: 60 * 60 * 1000,
      checkInterval: 1000,
    },
  });

  return null;
}

在业务组件中,点击埋点可以这样使用:

tsx
import { useTrackClick } from 'react-track-hooks';

function BuyButton() {
  const handleClick = useTrackClick('buy_button_click', {
    page: 'product_detail',
    module: 'footer_bar',
  });

  return <button onClick={handleClick}>立即购买</button>;
}

曝光埋点则更适合列表卡片或推荐模块:

tsx
import { useTrackExposure } from 'react-track-hooks';

function RecommendCard() {
  const ref = useTrackExposure<HTMLDivElement>('recommend_card_exposure', {
    cardId: 'card_001',
  });

  return <div ref={ref}>推荐内容</div>;
}

这种 API 设计把埋点逻辑从业务组件中抽离出来,业务代码只需要表达“这里要记录什么事件”,而不用关心发送、批量、失败重试等底层细节。

架构设计

react-track-hooks 的源码结构非常清晰,核心位于 src/track 目录。

项目目录可以概括为:

text
react-track-hooks
├── src
│   ├── index.ts                         # 包入口,统一导出类型、配置函数、核心函数和 Hooks
│   ├── types.ts                         # TrackType、TrackParams、TrackConfig 等核心类型
│   ├── utils.ts                         # 浏览器环境判断、localStorage 安全写入、事件 ID 生成
│   ├── track
│   │   ├── config.ts                    # 全局配置单例和配置合并逻辑
│   │   ├── core
│   │   │   ├── sendTrack.ts             # 单条埋点发送入口,决定单发或进入批量队列
│   │   │   ├── sendBatchTrack.ts        # 批量队列、定时上报、页面隐藏上报
│   │   │   └── retryTrack.ts            # 失败缓存、指数退避和重试逻辑
│   │   ├── hooks
│   │   │   ├── useTrack.ts              # 基础埋点 Hook,所有场景 Hook 的统一触发器
│   │   │   ├── useTrackClick.ts         # 点击埋点
│   │   │   ├── useTrackExposure.ts      # 曝光埋点
│   │   │   ├── useTrackPageStay.ts      # 页面停留时长埋点
│   │   │   ├── useTrackFirstRender.ts   # 首次渲染埋点
│   │   │   ├── useTrackCustom.ts        # 自定义埋点
│   │   │   └── useTrackInit.ts          # 初始化全局配置、批量上报和重试监听
│   │   └── listeners
│   │       └── useTrackRetryListener.ts # 全局失败重试监听器
│   └── __tests__                        # Vitest 测试用例和浏览器 API mock
├── dist                                 # Rollup 构建后的 CJS、ESM 和类型声明产物
├── rollup.config.js                     # 打包配置
├── tsconfig.json                        # TypeScript 配置
└── package.json                         # npm 包信息、脚本和 peer dependencies

这个目录结构体现了项目的分层思路:hooks 面向业务场景,core 负责上报和可靠性,config 管理全局策略,listeners 负责浏览器生命周期里的补偿重试,types 和 utils 则提供跨模块复用的基础能力。

对外入口是 src/index.ts,它统一导出类型、配置函数、核心函数和所有 Hooks。类型定义集中在 src/types.ts,包括 TrackType、TrackParams、TrackGlobalConfig、TrackConfig 和 FailedTrackParams。

配置层位于 src/track/config.ts。项目使用模块级单例维护全局配置,提供 setTrackGlobalConfig 和 getTrackGlobalConfig。全局默认配置会和用户传入配置合并,嵌套配置也会保留未覆盖字段,避免局部配置导致默认策略丢失。

基础 Hook 是 useTrack。所有业务 Hook 最终都会调用它。useTrack 接收统一的埋点参数和配置,返回 triggerTrack 方法。触发时,它会合并定义时参数和运行时额外参数,并把最终事件交给 sendTrack。

发送层由 sendTrack.ts 负责。它会先判断当前是否处于浏览器环境,再检查事件名和启用状态。如果开启批量模式,事件会进入内存队列;如果关闭批量模式,则直接通过 fetch 发送到 trackUrl。

批量上报由 sendBatchTrack.ts 管理。它维护一个内存队列 BATCH_TRACK_QUEUE,并通过队列长度和定时器两种方式触发上报。当页面进入隐藏状态时,它也会尝试立即处理队列,减少页面关闭导致的数据丢失。

失败重试由 retryTrack.ts 负责。发送失败的事件会保存到 localStorage.failedTracks 中,并记录重试时间和重试次数。后续重试使用指数退避策略,避免网络异常时持续高频请求。重试支持单条模式,也支持批量模式。

全局重试监听由 useTrackRetryListener 注册。它会在首屏渲染后延迟重试一次,在页面从隐藏变为可见时重试,也会利用 requestIdleCallback 在浏览器空闲时周期性检查失败队列。

整体调用链可以概括为:

text
业务组件
  -> useTrackClick / useTrackExposure / useTrackPageStay / useTrackCustom
  -> useTrack
  -> sendTrack
  -> 单条 fetch 或进入批量队列
  -> 失败写入 localStorage
  -> useTrackRetryListener 触发 retryFailedTracks

可靠性设计

埋点系统最重要的问题之一是可靠性。用户行为一旦发生,就很难重新采集,因此 SDK 需要尽量降低丢失概率。

react-track-hooks 在这方面做了几层设计。

首先是批量上报。批量模式可以减少网络请求数量,降低高频事件对页面性能和后端接口的压力。队列达到指定大小时会立即上报,同时也有定时器兜底,避免事件长时间滞留在内存中。

其次是页面隐藏处理。当页面关闭、切换标签页或进入后台时,库会监听 visibilitychange,在页面变为隐藏时尝试处理批量队列。单条发送和批量发送都使用了 keepalive,这有助于在页面卸载阶段完成请求。

第三是失败缓存。请求失败后,事件不会直接丢弃,而是写入 localStorage。为了避免存储无限增长,工具函数会控制数据体积,并保留较新的失败事件。

第四是指数退避重试。失败事件不会被立即无限重试,而是根据 initialDelay 和 delayMultiplier 计算下一次可重试时间,并受 maxRetryTimes 限制。这种机制在弱网或服务端短暂异常时更稳健。

第五是多触发点重试。重试不仅发生在下一次成功上报后,还会在首屏延迟、页面重新可见、浏览器空闲时间等时机触发,提高失败事件被补偿上报的概率。

对 React 项目的价值

对业务开发者来说,react-track-hooks 最大的价值是把埋点从“到处写 fetch”变成了“按场景使用 Hook”。这让代码更一致,也更容易维护。

例如,点击事件统一使用 useTrackClick,曝光事件统一使用 useTrackExposure,页面停留统一使用 useTrackPageStay。团队可以围绕这些 Hook 形成统一约定,而不是每个组件各写一套埋点实现。

对基础设施维护者来说,这个库把发送、批量、重试、失败缓存和公共参数补充集中在核心层。一旦上报协议、接口地址或重试策略变化,只需要调整 SDK 或全局配置,而不需要修改大量业务组件。

对 Next.js 项目来说,库内部通过 isClient 判断浏览器环境,避免在服务端渲染阶段访问 window、document 或 localStorage。这让它更容易放进 Next.js 的客户端组件或全局 Provider 中使用。

工程化与发布

react-track-hooks 使用 TypeScript 编写,并通过 Rollup 构建。构建产物同时提供 CommonJS 和 ES Module 格式,对应 dist/index.cjs.js 和 dist/index.esm.js,类型声明则通过 dist/index.d.ts 暴露。

项目将 react 和 react-dom 声明为 peer dependencies,不会打包进库中,避免使用方项目出现重复 React 实例。

测试方面,项目使用 Vitest 和 jsdom。测试环境中 mock 了 fetch、IntersectionObserver、requestIdleCallback 和 cancelIdleCallback,从而可以覆盖点击、曝光、页面停留、发送失败和重试等核心路径。

发布前脚本会依次执行类型检查、测试和构建:

bash
npm run typecheck
npm run test
npm run build

这套流程保证了库在发布前至少经过类型、行为和产物三方面验证。

适合的使用场景

react-track-hooks 适合需要快速接入前端埋点的 React 项目,尤其适合以下场景:

  • 需要统一管理点击、曝光、页面停留等常见行为事件。
  • 希望减少业务组件中的埋点样板代码。
  • 希望支持批量上报,降低网络请求压力。
  • 希望失败事件能缓存并自动重试,减少数据丢失。
  • 项目使用 React 或 Next.js,并希望以 Hook 的方式组织埋点逻辑。

它不试图替代完整的数据分析平台,也不绑定特定后端协议。只要后端提供单条或批量接收接口,前端就可以通过配置接入。

总结

react-track-hooks 是一个小而完整的前端埋点 SDK。它把 React Hook 的易用性和埋点系统需要的可靠性结合起来,既提供了面向业务场景的简洁 API,也在底层处理了批量上报、失败缓存、指数退避和自动重试。

如果用一句话概括这个项目:react-track-hooks 让 React 项目的埋点从分散、重复、易丢失的手写逻辑,变成了一套统一、可配置、可重试的 Hook 化采集方案。

评论
0/100