react-call:像 await 函数一样调用 React 组件

react-call 让模态框变成可 await 的函数调用:1KB、零依赖。本文讲解 createCallable 的三步用法与确认对话框完整实战。

最佳实践
Web 构建模块与工具协作插画

react-call 把"打开模态框等用户操作"变成 const ok = await Confirm.call({ title: '删除?' })——组件用 createCallable 包装后即可命令式调用并 await 结果,消灭可见性状态与回调链。

传统方式的痛点

一个确认对话框需要:可见性 state、上下文数据 state、确认/取消两个回调——触发组件在树深处时还要状态提升或 Context 穿透。三行能写完的逻辑膨胀成二十行。

react-call 三步走

npm install react-call
import { createCallable } from 'react-call';

// 1. 包装组件
const Confirm = createCallable<{ title: string }, boolean>(({ call, title }) => (
  <dialog open>
    <p>{title}</p>
    <button onClick={() => call.end(true)}>确认</button>
    <button onClick={() => call.end(false)}>取消</button>
  </dialog>
));

// 2. 挂载响应器(应用根部)
<Confirm.Root />

// 3. 像函数一样调用
async function handleDelete(item) {
  const ok = await Confirm.call({ title: `删除 ${item.name}?` });
  if (ok) await deleteItem(item);
}

核心概念

  • createCallable<Props, Result>:泛型声明入参与返回类型——类型安全贯通;
  • call.end(value):组件内结束调用并回传结果(Promise resolve);
  • .Root:渲染响应器的挂载点,类似 Portal 出口。

完整示例:删除确认

const Confirm = createCallable<{ title: string; danger?: boolean }, boolean>(
  ({ call, title, danger }) => (
    <div className="modal-mask">
      <div className="modal">
        <h3>{title}</h3>
        <button className={danger ? 'btn-danger' : ''} onClick={() => call.end(true)}>
          确认
        </button>
        <button onClick={() => call.end(false)}>取消</button>
      </div>
    </div>
  )
);

function App() {
  return (
    <>
      <ItemList />
      <Confirm.Root />
    </>
  );
}

任何层级的组件都能 await Confirm.call()——不需要把对话框状态提升到公共祖先。

常见问题(FAQ)

Q:与 Context + useReducer 方案比优势?

代码量与心智负担:调用即函数,结果即返回值。传统方案的"状态-回调-清理"模板代码全部消失。

Q:支持 toast、抽屉等其他组件吗?

任何"触发-响应"模式的组件都适合:确认框、toast、表单弹窗、引导提示。串行连续调用(向导流程)也可用 await 链表达。

Q:服务端渲染兼容吗?

兼容(Root 在客户端渲染)。Next.js App Router 项目把 Root 放进客户端组件边界即可。


参考文档

本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。

延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台