@churnkey/react

中文文档
0.10.0发布于 2026/11/03MITTypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 4873

生产准备取消流量 滴入组件,无头钩,或完全定制. 单独工作或与Churnkey一起工作,以保留AI动力.

中文使用文档
文档目录15 节
  1. 安装
  2. 创建取消流量
  3. 改变外观
  4. 替换组件
  5. 添加自定义步骤
  6. 预建定制出价组件
  7. 无头去
  8. 添加分析
  9. 让Churnkey处理账单
  10. 处理器对听众
  11. 报价对等
  12. 传递客户/订阅数据并附带一个令牌
  13. 混合本地和服务器步骤
  14. 进口
  15. 许可证

@ churnkey/ 反应

React 的取消流量组件 。 调查、提议、反馈和确认。 准备用出盒子,在需要的时候可以完全定制.

开源. 可选连接到 Rn克 分析学和人工智能能力保留.

安装

npm install @churnkey/react

创建取消流量

导入组件和样式表,定义您的步骤,并处理结果.

import { CancelFlow } from '@churnkey/react'
import '@churnkey/react/styles.css'

<CancelFlow
  steps={[
    {
      type: 'survey',
      title: 'Why are you leaving?',
      reasons: [
        {
          id: 'expensive',
          label: 'Too expensive',
          offer: {
            type: 'discount',
            couponId: 'STRIPE_SAVE20',  // your coupon ID
            percentOff: 20,             // for the UI
            durationInMonths: 3,        // for the UI
          },
        },
        {
          id: 'not-using',
          label: 'Not using it enough',
          offer: { type: 'pause', months: 2 },
        },
        { id: 'missing', label: 'Missing features' },
      ],
    },
    { type: 'feedback', title: 'Anything else?' },
    { type: 'confirm' },
  ]}
  handleDiscount={async (offer) => myBilling.applyCoupon(offer.couponId)}
  handlePause={async (offer) => myBilling.pause({ months: offer.result?.months ?? offer.months })}
  handleCancel={async () => myBilling.cancel()}
  onClose={() => setOpen(false)}
/>

当客户选择"太贵"时,SDK会显示折扣报价. 如果他们接受了, handleDiscount 运行。 如果他们拒绝所有的报价和确认, handleCancel 运行.

改变外观

SDK飞船的轻而易举和黑暗计划. 'auto' 跟踪用户的OS偏好,并对变化作出反应.

<CancelFlow
  appearance={{ colorScheme: 'auto' }}
  steps={steps}
  onAccept={handleOffer}
  onCancel={handleCancel}
/>

覆盖通过 appearance.variables同样的价值在两种方案中都适用——一次设定出你的品牌颜色,然后随处可见.

appearance={{
  variables: { colorPrimary: '#7c3aed', borderRadius: '12px' },
}}

基于类的样式( Tailwind, CSS 模块), 使用 classNames数字 :

classNames={{
  modal: 'max-w-lg shadow-2xl',
  overlay: 'bg-black/60 backdrop-blur-sm',
}}

替换组件

换掉任何UI的一部分。 SDK处理导航和状态;你处理渲染.

<CancelFlow
  steps={steps}
  components={{
    ReasonButton: ({ reason, isSelected, onSelect }) => (
      <button
        onClick={() => onSelect(reason.id)}
        className={isSelected ? 'border-blue-500 bg-blue-50' : 'border-gray-200'}
      >
        {reason.label}
      </button>
    ),
  }}
  onAccept={handleOffer}
  onCancel={handleCancel}
/>

您可以替换 Modal, (中文(简体) ), CloseButton, (中文(简体) ), BackButton,步骤组件Survey, (中文(简体) ), Offer, (中文(简体) ), Feedback, (中文(简体) ), Confirm, (中文(简体) ), Success, (中文(简体) ), ReasonButton每发价类型的组件(DiscountOffer, (中文(简体) ), PauseOffer, (中文(简体) ), PlanChangeOffer, (中文(简体) ), TrialExtensionOffer, (中文(简体) ), ContactOffer, (中文(简体) ), RedirectOffer),以及 StackedOffer 为一对报价.

添加自定义步骤

台阶系统开放. 使用任意字符串作为步骤类型,然后为它注册一个组件.

<CancelFlow
  steps={[
    { type: 'survey', reasons: [
      { id: 'seats', label: 'Too many seats',
        offer: { type: 'change-seats', data: { minSeats: 1 } } },
    ]},
    { type: 'nps', title: 'One quick question', data: { scale: 10 } },
    { type: 'feedback' },
    { type: 'confirm' },
  ]}
  customComponents={{
    'nps': ({ step, onNext }) => (
      <NpsRating scale={step.data.scale} onSubmit={(score) => onNext({ score })} />
    ),
    'change-seats': ({ offer, onAccept }) => (
      <SeatAdjuster onConfirm={(seats) => onAccept({ seats })} />
    ),
  }}
  onAccept={handleOffer}
  onCancel={handleCancel}
/>

自定义步骤像内置步骤一样导航 。 自定义要约在选择匹配原因时出现 。 无论你传递给什么 onNext(result) 或者说 onAccept(result) 现身 offer.result 在你身边 onAccept 处理器,并记录在分析会话中(如: customStepResults[stepType] 步骤, acceptedOffer.customOfferResult (关于要约).

预建定制出价组件

如果你不想自己建定制的UI, 导入一个预建的 @churnkey/react/recipes它们采用与内置报价相同的造型系统,并将结果通过 onAccept,所以你只执行计费部分.

import { TermExtensionOffer, PassthroughOffer } from '@churnkey/react/recipes'

<CancelFlow
  customComponents={{
    // "Delay your next charge by N days". Reads offer.data.days, shows the
    // new renewal date, passes { days } through onAccept.
    annual_term_extension: TermExtensionOffer,
    // Copy + accept/decline, nothing else. Register it for any offer type
    // whose substance lives entirely in the flow-authored copy; offer.data
    // passes through as the result.
    scheduled_transfer: PassthroughOffer,
    immediate_transfer: PassthroughOffer,
  }}
  onAccept={handleOffer}
  onCancel={handleCancel}
/>

组件位于子路径导出后, 因此除非导入, 否则不会添加到您的捆绑中 。 要进行完整的演示文稿控制,请从 packages/react/examples/ 转而进入你的密码库 从那里拥有它.

无头去

如果要完全控制UI,直接使用钩子.

import { useCancelFlow } from '@churnkey/react/headless'

function MyCancelPage() {
  const flow = useCancelFlow({ steps, onAccept: handleOffer, onCancel: handleCancel })

  if (flow.step === 'survey') {
    return (
      <div>
        {flow.reasons.map((r) => (
          <button key={r.id} onClick={() => flow.selectReason(r.id)}>{r.label}</button>
        ))}
        <button onClick={flow.next} disabled={!flow.selectedReason}>Continue</button>
      </div>
    )
  }

  if (flow.step === 'offer' && flow.currentOffer) {
    return (
      <div>
        <h2>{flow.currentOffer.copy.headline}</h2>
        <button onClick={flow.accept}>Accept</button>
        <button onClick={flow.decline}>No thanks</button>
      </div>
    )
  }

  // ... feedback, confirm, success
}

钩子返回当前状态( T)step, (中文(简体) ), reasons, (中文(简体) ), currentOffer, (中文(简体) ), feedback, (中文(简体) ), outcome, (中文(简体) ), isProcessing和行动selectReason, (中文(简体) ), next, (中文(简体) ), back, (中文(简体) ), accept, (中文(简体) ), decline, (中文(简体) ), cancel, (中文(简体) ), close) (中文(简体) ).

在象征性模式中,钩子会留下一对报价,除非你通过 stackedOffers: true; 见 报价对等。 。 。 .

添加分析

创建一个 免费 Churnkey 账户 并通过你的 appId。SDK记录每个会话,这样你就可以知道为什么客户取消,提供工作,以及你的储蓄率是什么样子.

<CancelFlow
  appId="app_xxx"
  customer={{ id: 'cus_123' }}
  steps={steps}
  onAccept={handleOffer}
  onCancel={handleCancel}
/>

仅 customer.id 需要时间。 关于收入衡量标准,也通过订阅数据:

<CancelFlow
  appId="app_xxx"
  customer={{ id: 'cus_123', email: '[email protected]' }}
  subscriptions={[{
    id: 'sub_456',
    start: '2024-06-01',
    status: { name: 'active', currentPeriod: { start: '2025-04-01', end: '2025-05-01' } },
    items: [{ price: { id: 'price_pro', amount: { value: 2999 } } }],
  }]}
  steps={steps}
  onAccept={handleOffer}
  onCancel={handleCancel}
/>

你的步骤和召回不会改变。 不需要后端工作 .

当客户接受要约、确认取消或完成(放弃)之前关闭模式时,会话记录。 从自定义步骤通过的数据 onNext(result) 与会议同时进行.

为了保持交通 出你的生产分析,通过 mode="test"数字 :

<CancelFlow
  appId="app_xxx"
  customer={{ id: 'cus_123' }}
  mode={process.env.NODE_ENV === 'production' ? 'live' : 'test'}
  steps={steps}
  onAccept={handleOffer}
  onCancel={handleCancel}
/>

默认为 'live'。如果您的矿石连接到一个 花边沙盒 而不是经典测试模式,通过 mode="sandbox" 而不是服务器侧的帐单操作 使用您的沙盒证书。 在指使模式中,指使模式优先——它是服务器签名的,不能被压倒客户端侧面.

让Churnkey处理账单

在Churnkey仪表板上连接您的计费供应商(Stripe,Chargebee等),Churnkey可以应用折扣,暂停订阅,并代表您取消. 在您的服务器上生成一个令牌以认证会话 .

// Server
import { Churnkey } from '@churnkey/node'

const ck = new Churnkey({ appId: 'app_xxx', apiKey: 'sk_xxx' })
const token = ck.createToken({ customerId: 'cus_123' })
// Client
<CancelFlow
  appId="app_xxx"
  customer={{ id: 'cus_123', email: '[email protected]' }}
  subscriptions={[...]}
  session={token}
  onAccept={async (offer) => console.log('Applied:', offer)}
  onCancel={async () => router.push('/goodbye')}
/>

在此模式下,取消流由Churnkey仪表板配置. 您的自定义组件和外观设置继续 .

处理器对听众

两种回叫,用名来区分:

  • handle<Type> - 运行动作。 替换 Churnkey 在服务器上所做的 。 在本地模式( 无令牌 ) 中, 这是唯一运行动作 .
  • on<Type> ——行动后起火,无论是谁指挥. 副作用只有——分析,回放,土司.
<CancelFlow
  session={token}
  // Handler: defining handlePause tells the SDK NOT to call its own
  // server-side pause; you run the action instead. Skip handle* and
  // Churnkey takes the action automatically in token mode.
  handlePause={async (offer, customer) => {
    await myBilling.pause({ months: offer.result?.months ?? offer.months })
  }}
  // Listener: fires after the pause completes (whoever ran it).
  onPause={(offer, customer) => analytics.track('paused', { months: offer.result?.months ?? offer.months })}
  onAccept={(offer) => analytics.track('offer_accepted', { type: offer.type })}
  onCancel={() => router.push('/goodbye')}
/>

可用的处理器 : handleDiscount, (中文(简体) ), handlePause, (中文(简体) ), handlePlanChange, (中文(简体) ), handleTrialExtension, (中文(简体) ), handleCancel。可用的听众 : onDiscount, (中文(简体) ), onPause, (中文(简体) ), onPlanChange, (中文(简体) ), onTrialExtension, (中文(简体) ), onCancel,加上包罗万象 onAccept 任何被接受的报价.

单位 本地模式 (没有标志),没有服务器动作——处理者做活. 单位 符号模式定义一个操作员选择退出运行动作的Churnkey,并将工作还给你.

报价对等

报价可携带第二个报价(offer.stackedOffer),设置在仪表板上. SDK显示每张出价一张卡和一个单个"接受两个出价"按钮;通过: StackedOffer 组件槽.

Churnkey只向一个显示两种报价的UI发送一对. 和你自己一样 Offer 组件,或 a customComponents 输入内置要约类型,对子不包含在流量中,除非您也通过 StackedOffer与 useCancelFlow,通过 stackedOffers: true 一旦你的UI让 offer.stackedOffer。 。 。 .

  • 没有处理器,令牌模式在一项请求中同时适用两种要约. 在暂停或延长审判后,第二次提议在暂停或审判结束后开始.
  • 与处理者,每出价通过自己的处理者,先出价,但退价最后出价. 如果第二顺位的报价失败了, 流量仍然完成, acceptedOffer.stackedOffer.stackStatus 实值 'failed' 财务报告和审定财务报表 failedOfferType 列出不适用的报价。 只有Churnkey在暂停或试运行时可以持有第二个报价,因此在本地模式中,当一个处理者覆盖任一报价时,一对其第二个报价等待被忽略出流量. 在象征性模式中,当处理者只覆盖其一项要约时,一对也会被排除在外,因为Churnkey只将一对要约与另一对一起应用.
  • 听众和 onAccept 得到每个报价 自己, 一旦适用报价.
  • A 类 StackedOffer 组件接受配对并有一个结果: months 用于暂停和 planId 计划改变。 每个报价 result 只有自己的选择,加上你通过的任何其他钥匙.

传递客户/订阅数据并附带一个令牌

你可以通过 customer 财务报告和审定财务报表 subscriptions 合并 session 用客户端数据来丰富会话记录的Churnkey还没有(海关元数据,当前计划价格等). 指使牌上签名的客户ID保持权威;直接数据填补了空白.

<CancelFlow
  appId="app_xxx"
  customer={{ id: 'cus_123', email: '[email protected]', metadata: { plan: 'pro' } }}
  subscriptions={[...]}
  session={token}
  onAccept={handleOffer}
  onCancel={handleCancel}
/>

混合本地和服务器步骤

你可以通过两个 session 财务报告和审定财务报表 steps 以覆盖特定的服务器配置 :

<CancelFlow
  session={token}
  steps={[
    { type: 'confirm', title: 'We hate to see you go' },
    { type: 'nps', title: 'Quick question', data: { scale: 10 } },
  ]}
  customComponents={{ 'nps': NpsStep }}
  onAccept={handleOffer}
  onCancel={handleCancel}
/>

本地步骤按类型覆盖 。 未在服务器配置中的步骤会被附加 .

进口

import { CancelFlow } from '@churnkey/react'              // drop-in component
import { useCancelFlow } from '@churnkey/react/headless'   // headless hook
import { CancelFlowMachine } from '@churnkey/react/core'   // state machine, no React
import { TermExtensionOffer } from '@churnkey/react/recipes' // prebuilt custom-offer components

许可证

麻省理工学院

版本与发布记录

@churnkey/react 共发布 23 个版本,首次发布于 2026/05/01;过去 12 个月发布了 23 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.10.0latest2026/11/036 天前
0.9.12026/10/2911 天前
0.9.02026/10/2218 天前
0.8.12026/10/091 个月前
0.8.02026/07/223 个月前
0.7.22026/07/163 个月前

关于 @churnkey/react 的常见问题

@churnkey/react 是什么?

生产准备取消流量 滴入组件,无头钩,或完全定制. 单独工作或与Churnkey一起工作,以保留AI动力.

如何安装 @churnkey/react?

在项目目录运行 npm install @churnkey/react,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^18.0.0 || ^19.0.0)、react-dom(^18.0.0 || ^19.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@churnkey/react 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@churnkey/react 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@churnkey/react 可以商用吗?

@churnkey/react 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@churnkey/react 的下载量有多少?

根据 npm 官方下载统计,@churnkey/react 在 2026/10/10 – 2026/11/08 这 30 天内被下载 4,873 次,日均约 162 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@churnkey/react 还在维护吗?

最新版本 0.10.0 发布于 2026/11/03(6 天前);至今共发布 23 个版本,其中过去 12 个月发布了 23 个;首次发布于 2026/05/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。