The react-call library allows you to turn a React component into something you can await imperatively. The workflow follows three distinct steps:
- Declare: Use
createCallable<Props, Response, RootProps>() to define your component. The component receives a special call prop (the CallContext) which provides methods to resolve the interaction. - Root: Mount the resulting Callable component (the Root) exactly once in a high-level part of your application (e.g.,
App.tsx or a layout) so it is always available to receive calls. - Call & await: Invoke the component's namespace methods (like
.call()) from anywhere in your async code to trigger the UI and await its result.
Generics for createCallable:
Props: The props passed to each individual call.Response: The type of value the promise resolves to.RootProps (optional): Props passed to the Root component itself for data shared across all calls.
import { createCallable } from 'react-call'
interface Props { message: string }
type Response = boolean
// 1. Declare
export const Confirm = createCallable<Props, Response>(({ call, message }) => (
<div role="dialog">
<p>{message}</p>
<button onClick={() => call.end(true)}>Yes</button>
<button onClick={() => call.end(false)}>No</button>
</div>
))
// 2. Root (Mount once in App.tsx)
// <Confirm />
// 3. Call & await
const accepted = await Confirm.call({ message: 'Continue?' })