React 封装
在 TypeScript SDK 之上的一个 Provider 和两个 Hook。它每页只安装一个客户端,因此 React 严格模式不会让你的事件翻倍。
发布位置
@prodantix/react on npm. It wraps @prodantix/sdk, so install both.
安装
bun add @prodantix/sdk @prodantix/react| Export | What it is |
|---|---|
| ProdantixProvider | Creates the client once per page and provides it |
| useProdantix | The client for the page, or null |
| useMessenger | A handle that opens and closes the widget, or null |
| prodantixConfig | The config when both key and host are present, else null |
| skipReason | Why this mount will send nothing, or null |
| resetProdantixForTest | Clears the once-per-page install, for tests |
Provider
把 ProdantixProvider 挂载一次,放在靠近根的位置。它在首次挂载时创建 Web 客户端,之后一直复用,因为创建第二个会给 History API 打两次补丁,把每个自动采集的事件都变成两份。
import { ProdantixProvider } from '@prodantix/react';
export const Providers = ({ children }: { children: ReactNode }) => (
<ProdantixProvider
options={{
apiKey: process.env.NEXT_PUBLIC_PRODANTIX_KEY,
host: 'https://eu.api.prodantix.com',
messengerHost: 'https://eu.edge.prodantix.com',
}}
>
{children}
</ProdantixProvider>
);指明已登录的人
person 告诉 provider 谁已登录,它是一个 prop 而不是一次调用,所以登录与登出会以它们本来的值抵达客户端。它有三种状态,每一种说的都不一样。undefined 表示这个界面还不知道,因为它的鉴权仍在水合,provider 什么都不做。有值则表示识别:provider 在第一个值上调用 identify,并在 distinctId 每次变化时再次调用,带上 SDK 自己的特征,即头像、邮箱、姓名与电话。null 表示该界面查过会话并且没有找到人,于是 provider 只在客户端仍处于已识别状态时才重置它,这会轮换匿名 id,使这台浏览器上的下一位访客不再是刚刚登出的那个人。正是这一条让登出在“登出即硬跳转、从有值到 null 的过渡永远不会渲染”的地方仍然生效。这也是 null 绝不能表示加载中的原因:一个已登录的人刷新页面时,会在鉴权水合之前就被重置。完全不查会话的挂载,比如一个落地页或一份文档页,应传 undefined;而缺失的 prop 本来就读作 undefined。
import { ProdantixProvider } from '@prodantix/react';
export const Providers = ({ children }: { children: ReactNode }) => {
const { session, status } = useSession();
// undefined while auth hydrates, null once it has resolved to nobody,
// the subject once it has resolved to someone.
const person = status === 'loading' ? undefined : session ? { distinctId: session.sub } : null;
return (
<ProdantixProvider
options={{
apiKey: process.env.NEXT_PUBLIC_PRODANTIX_KEY,
host: 'https://eu.api.prodantix.com',
person,
}}
>
{children}
</ProdantixProvider>
);
};两个 Hook
useProdantix 返回该页的客户端;在服务端、在 effect 运行之前,以及在 Provider 之外,它返回 null。useMessenger 返回打开和关闭挂件的句柄,在读取到项目配置并确认已启用之前一直是 null。
import { useMessenger, useProdantix } from '@prodantix/react';
export const HelpButton = () => {
const prodantix = useProdantix();
const messenger = useMessenger();
// Both are null until the provider effect has run, so neither is assumed.
return (
<button
onClick={() => {
prodantix?.capture('help.opened');
messenger?.open();
}}
type="button"
>
Get help
</button>
);
};当它什么都不发送时
即使关闭 Prodantix,应用也照样发布,因此缺少 key 或 host 并不是错误。prodantixConfig 告诉你两个值是否齐备,skipReason 则用一行说明这次挂载为什么什么都不会发,而不是悄悄返回。
import { prodantixConfig, skipReason } from '@prodantix/react';
const env = {
host: process.env.NEXT_PUBLIC_PRODANTIX_HOST,
key: process.env.NEXT_PUBLIC_PRODANTIX_KEY,
};
// null when either value is missing: the app runs with Prodantix switched off.
if (prodantixConfig(env) === null) {
console.warn(skipReason(env, null));
}