跳到主要内容

React 封装

在 TypeScript SDK 之上的一个 Provider 和两个 Hook。它每页只安装一个客户端,因此 React 严格模式不会让你的事件翻倍。

发布位置

@prodantix/react on npm. It wraps @prodantix/sdk, so install both.

安装

Bash
bun add @prodantix/sdk @prodantix/react
ExportWhat it is
ProdantixProviderCreates the client once per page and provides it
useProdantixThe client for the page, or null
useMessengerA handle that opens and closes the widget, or null
prodantixConfigThe config when both key and host are present, else null
skipReasonWhy this mount will send nothing, or null
resetProdantixForTestClears the once-per-page install, for tests

Provider

把 ProdantixProvider 挂载一次,放在靠近根的位置。它在首次挂载时创建 Web 客户端,之后一直复用,因为创建第二个会给 History API 打两次补丁,把每个自动采集的事件都变成两份。

TypeScript
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>
);
只有当你传入 messengerHost 且项目在控制台里开启了它时,消息助手才会出现。既没有配置也没有缓存时什么都不渲染,因为默认样式的启动按钮只是画在客户页面上的猜测。

指明已登录的人

person 告诉 provider 谁已登录,它是一个 prop 而不是一次调用,所以登录与登出会以它们本来的值抵达客户端。它有三种状态,每一种说的都不一样。undefined 表示这个界面还不知道,因为它的鉴权仍在水合,provider 什么都不做。有值则表示识别:provider 在第一个值上调用 identify,并在 distinctId 每次变化时再次调用,带上 SDK 自己的特征,即头像、邮箱、姓名与电话。null 表示该界面查过会话并且没有找到人,于是 provider 只在客户端仍处于已识别状态时才重置它,这会轮换匿名 id,使这台浏览器上的下一位访客不再是刚刚登出的那个人。正是这一条让登出在“登出即硬跳转、从有值到 null 的过渡永远不会渲染”的地方仍然生效。这也是 null 绝不能表示加载中的原因:一个已登录的人刷新页面时,会在鉴权水合之前就被重置。完全不查会话的挂载,比如一个落地页或一份文档页,应传 undefined;而缺失的 prop 本来就读作 undefined。

TypeScript
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。

TypeScript
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 则用一行说明这次挂载为什么什么都不会发,而不是悄悄返回。

TypeScript
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));
}