codeType
1. 讲了一下埋点库,出发点与考量。能不能有办法让埋点逻辑彻底从ui层面抽离。
2. 手动实现一下悬浮埋点和曝光埋点hooks的实现。
3. 手动实现失败重试函数的代码
4. git rebase
5. ai辅助开发实践
6. 反问公司现在最前沿的ai辅助开发实践
1. 有没有办法让埋点逻辑彻底从ui代码中抽离
主要提出了两种方式
- 用全埋点的方式
- 单独做一层业务层,把参数配置(事件的名字,参数,触发类型)的步骤统一到一个地方。然后封装一个通用的hooks,可以根据配置的参数去触发不同的hooks。然后在组件直接触发就行。这样在组件层面就不需要关心具体的用哪种hooks、参数如何配置。埋点业务参数集中也好管理。
2. 实现悬浮埋点和曝光埋点hooks
以下是悬浮埋点实现的方式,具体的获取配置和进行上报都提前封装好了。面试时写的跟这个差不多,面试后考虑了一下发现有闭包问题,所以用ref解决了一下。
tsx
import {getTrackGlobalConfig} from "../config";
import {useCallback, useEffect, useRef} from "react";
import { sendTrack } from "../core/sendTrack";
const useTrackHover = (params, config) => {
const mergeConfig = {...getTrackGlobalConfig(), config};
const targetRef = useRef(null);
const latestParamsRef = useRef(params);
const latestConfigRef = useRef(mergeConfig);
latestParamsRef.current = params
latestConfigRef.current = mergeConfig
const handleFuc = useCallback(() => {
sendTrack(latestParamsRef.current, latestConfigRef.current)
}, [])
useEffect(() => {
if(!targetRef.current) return
const ele = targetRef.current
ele.addEventListener("mouseenter", handleFuc);
return () => {
ele.removeEventListener("mouseenter", handleFuc)
}
}, []);
return targetRef
}
下面是我埋点库中的代码实现,曝光埋点主要就是通过IntersectionObserver这个类实现的。
ts
import {TrackConfig, TrackType} from "../../types";
import {getTrackGlobalConfig} from "../config";
import {useTrack} from "./useTrack";
import {useEffect, useRef} from "react";
/**
* 曝光埋点 Hook - 封装元素曝光埋点逻辑,返回需要监听的 DOM 引用
* @template T 目标元素类型(默认:HTMLElement)
* @param eventName 曝光事件名称(必填)
* @param customParams 自定义埋点参数(可选)
* @param config 埋点配置项(可选,支持曝光阈值、是否只上报一次等)
* @returns 需绑定到目标元素的 Ref 对象
*/
export const useTrackExposure = <T extends HTMLElement = HTMLElement>(
eventName: string,
customParams: Record<string, any> = {},
config: TrackConfig = {}
) => {
const mergedConfig = { ...getTrackGlobalConfig(), ...config };
const { triggerTrack } = useTrack(
{ eventName, type: TrackType.EXPOSURE, ...customParams },
mergedConfig
);
const latestConfigRef = useRef(mergedConfig)
const targetRef = useRef<T>(null);
const hasReported = useRef(false);
useEffect(() => {
if (!latestConfigRef.current.enable) return;
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !hasReported.current) {
const exposureParams = {
intersectionRatio: entry.intersectionRatio,
boundingClientRect: entry.boundingClientRect,
exposureTime: Date.now()
};
triggerTrack(exposureParams);
if (latestConfigRef.current.exposureOnce) {
hasReported.current = true;
observer.unobserve(entry.target);
}
}
});
},
{ threshold: latestConfigRef.current.exposureThreshold }
);
const target = targetRef.current;
if (target) observer.observe(target);
return () => {
if (target) observer.unobserve(target);
observer.disconnect();
};
}, [triggerTrack]);
return targetRef;
};
3. 失败重试函数的实现
我主要是通过递归的方式实现的