React 高阶组件实现埋点

React 高阶组件实现埋点

功能需求:

老板希望可以看到,我们做的系统的访问量,以及各个功能模块的被点击次数。

相关技术:

高阶组件和普通组件的区别:

定义和用途

  1. 普通组件
    • 定义:普通组件可以是函数组件或类组件,用于定义UI结构和交互逻辑。
    • 用途:主要用于渲染UI,展示数据和处理用户交互。
  2. 高阶组件(HOC)
    • 定义:高阶组件是一个函数,接受一个组件并返回一个新的组件。
    • 用途:用于复用组件逻辑,将公共的功能封装起来,可以增强或修改传入组件的行为。

代码示例

  1. 普通组件
jsx复制代码// 函数组件
const MyComponent = (props) => {
  return <div>Hello, {props.name}!</div>;
};

// 类组件
class MyComponent extends React.Component {
  render() {
    return <div>Hello, {this.props.name}!</div>;
  }
}
  1. 高阶组件(HOC)
jsx复制代码// 高阶组件
const withExtraProps = (WrappedComponent) => {
  return (props) => {
    return <WrappedComponent {...props} extraProp="I am an extra prop!" />;
  };
};

// 使用高阶组件增强普通组件
const EnhancedComponent = withExtraProps(MyComponent);

// 渲染EnhancedComponent将会渲染MyComponent并传入额外的属性
<EnhancedComponent name="World" />;

使用方式

  • 普通组件:直接定义并使用,可以在任何地方直接渲染。
  • 高阶组件:通过传入一个组件并返回一个新的组件来使用,通常用于为现有组件添加功能。

抽象级别

  • 普通组件:关注具体的UI和交互。
  • 高阶组件:关注逻辑复用和功能增强,通常不会直接定义UI。

渲染

  • 普通组件:直接渲染UI。
  • 高阶组件:返回一个包裹了原组件的新组件,并在新组件中添加逻辑。

为什么要用高阶组件

  1. 逻辑复用:可以将公共逻辑抽取出来,避免在多个组件中重复代码。
  2. 解耦:将特定功能与组件的核心逻辑分离,使代码更清晰、更易维护。
  3. 增强组件:可以在不修改原组件的情况下,增强其功能。

实现埋点功能

实现的核心代码逻辑如下所示:

_addEventDot函数主要实现的是打点的逻辑。这个逻辑也不复杂,就是获取相关的事件名称和用户信息,传给后端即可。

再看下面代码,可以看到里面的内容实现了两次return:

  1. WithInnerPlayer组件return 出来的<WrappedComponent/>
  2. WithTracking组件return出来的WithInnerPlayer

让我们来具体解释一下这两层 return 的作用:

  1. 内部组件 (WithInnerPlayer):
    • 这个内部组件是被 WithTracking HOC 创建的新组件,它接收原始组件 (WrappedComponent) 的所有属性,并添加了一些额外的功能(在这个例子中是追踪功能)。
    • WithInnerPlayer 组件的主要职责是接受来自外部的属性 (props),并将其与新添加的功能一起传递给 WrappedComponent
  2. 外部 HOC (WithTracking):
    • 这个 HOC 是一个工厂函数,它接收一个组件 (WrappedComponent) 并返回一个新的组件 (WithInnerPlayer)。
    • WithTracking 被调用时,它会创建并返回 WithInnerPlayer,这个内部组件已经包含了追踪功能。
import React from 'react';
import { v4 as uuidv4 } from 'uuid';
import moment from 'moment/moment';

import { addEventDot } from '@/services/api';
import { _getPhoneModel } from '@/utils/utils';
import CONFIG from 'GlobalConfigFile';


const DEFAULT_SERVER = process.env.DEFAULT_SERVER || CONFIG.Server;

const WithTracking = (WrappedComponent) => {
  const WithInnerPlayer = ({ ...props }) => {
    const { name } = WrappedComponent;
    const ua = _getPhoneModel();

    const _addEventDot = (params) => {
      const uuid = uuidv4();
      const trackingParams = {
        id: uuid,
        source: 'browser',
        occurOn: moment().unix() * 1000,
        project: 'EAP',
        env: DEFAULT_SERVER,
        deviceId: ua,
        ...params,
        name: params?.name || name,
      };
      addEventDot(trackingParams)
    };

    return <WrappedComponent handleAddEventDotClick={_addEventDot} {...props} />;
  };

  return WithInnerPlayer;
};

export default WithTracking;

如果只返回一层组件WithInnerPlayer会怎么样?

这种做法并不符合 HOC 的常规使用方式。在标准的 HOC 设计模式中,您希望返回一个增强过的组件,该组件保留了原始组件的所有特性,同时还添加了新的功能。

使用高阶组件

import MyComponent from './MyComponent';
import WithTracking from './WithTracking';

const TrackedMyComponent = WithTracking(MyComponent);

// 在其他组件中使用 TrackedMyComponent
function App() {
  return <TrackedMyComponent />;
}

或者如果有自定义的打点参数要传的话:

import WithTracking from './WithTracking';

function TrackedMyComponent(props) {
	const { handleAddEventDotClick } = props;
	
	...
	handleAddEventDotClick({
        name: 'visit:consult/appointment',
        props: {
          eventName: '咨询:访问预约(客服)'
        }
      });
     ...
}

export default WithTracking(TrackedMyComponent);
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值