Skip to content
tutorials

React's New Modal Killer Has Arrived

Managing modals and dialogs in React often leads to a tangled mess of props and state. A tiny utility called react-call completely changes the game by letting you call components like simple async functions.

Dani Roth
Hero image for: React's New Modal Killer Has Arrived

TL;DR / Key Takeaways

  • Managing modals and dialogs in React often leads to a tangled mess of props and state.
  • A tiny utility called react-call completely changes the game by letting you call components like simple async functions.

The Spaghetti Code We All Write

Managing interactive UI in React quickly devolves into a tangled mess. Developers routinely prop drill common `isOpen` states and `onClose` handlers deep into the component tree, passing them through layers of unrelated components. This forces parent components to manage child UI visibility, even when they have no direct concern, obscuring intent and complicating component reusability across the application.

This widespread pattern tightly couples UI state with core business logic, scattering control across numerous files. The result is classic spaghetti code, where a simple confirmation modal or multi-step form wizard becomes a web of interconnected `useState` calls and `useEffect` hooks. Such tightly bound logic is difficult to trace, debug, and refactor, turning minor UI adjustments into significant development efforts.

Traditional solutions like the Context API or React Portals offer only partial relief for these issues. Context requires verbose providers and consumers, adding significant boilerplate; Portals isolate DOM elements but provide no inherent solution for state management or control flow. Crucially, neither fundamentally solves the core architectural challenge: calling a UI component like an asynchronous function that returns a direct, actionable value, forcing developers into disconnected, callback-heavy approaches.

Call Components Like Async Functions

`react-call` redefines interactive UI management. It mirrors the native browser's `window.confirm` API, allowing components to pause execution, bringing an intuitive, blocking model directly into modern React.

Invoke components like async functions: `await Confirm.call()`. Execution pauses, awaiting user input—like an OK or Cancel click—before resuming. This keeps business logic linear and local to the calling component, simplifying complex workflows.

Architecture shifts dramatically. Eliminate `isModalOpen` state variables, removing prop drilling. Drop `onClose` or `onSubmit` callbacks. No longer require complex context providers or portals for interactive UI elements.

A callable component, wrapped with `createCallable`, acts as its own mounting point. Place it as a root tag anywhere visible; it sits as a listener. `react-call` manages multiple active instances via an internal stack, handling rendering and exit animations.

Under the hood, `react-call` abstracts promise management and handles typed requests/responses out-of-the-box. This lightweight utility is under 500B with zero dependencies. Full hot module replacement support maintains fast development cycles.

Inside the `react-call` Architecture

A single Root component forms `react-call`'s foundation, acting as its own mounting point. Place this callable component as a root tag anywhere visible in your application, like `App.js`, where it sits as a passive listener. When multiple calls trigger, `react-call` manages them via an internal stack, handling rendering, clean exit animations, and ensuring instance isolation automatically.

Upsert provides a critical pattern for singleton UI elements, like global notification toasts or loading overlays. While `call()` pushes new instances, `upsert()` prevents duplication for components where only one instance should be active. If an instance is on screen, `upsert` smoothly updates the existing component with new data on the fly, avoiding redundant UI and ensuring controlled, single-instance rendering.

Connect UI directly to backend actions using the Mutation Flow concept and its `useMutationFlow` hook. This hook automatically manages pending states, ensuring your callable UI, like a confirmation modal, remains open with a loading spinner while an async function runs. The call resolves and closes only once the underlying promise successfully completes, effectively bridging UI state and data mutations. This explicit control, including manual `call.end()`, allows robust error handling and retry mechanisms without losing user context. Explore more advanced patterns on react-call.

The Practical Payoff

Deploy `react-call` fast. Its footprint is minimal: <500B with zero dependencies, ensuring negligible bundle size impact. Wrap any React component with the `createCallable` higher-order component to instantly transform it into an awaitable UI primitive, ready for direct invocation.

Move beyond simple confirmations. `react-call` excels at orchestrating complex interactive flows. Implement: - Multi-step wizards - Dynamic item pickers - Asynchronous form submissions with integrated loading states

Utilize the `useMutationFlow` hook to seamlessly tie callable UI to backend actions, managing pending states and ensuring the UI remains active until promises resolve.

This isn't merely another modal library. `react-call` represents a fundamental shift in how you manage component interaction. It eliminates state-heavy boilerplate, declutters your frontend toolkit, and delivers a cleaner, more readable architecture. Embrace the paradigm shift; rethink your UI.

Frequently Asked Questions

What is react-call?

It's a lightweight utility that allows developers to call React components, like modals or dialogs, as if they were asynchronous functions, returning a promise that resolves with user input.

How does react-call differ from using React Context for modals?

react-call eliminates the need for a global context provider to manage modal state. It localizes the business logic to the calling component, avoiding prop drilling and complex state management.

What is the 'Upsert' feature in react-call for?

Upsert is for singleton UI patterns like toasts or loading spinners. It updates an existing component instance with new data instead of creating a new one, ensuring only one is on screen at a time.

Is react-call suitable for server-side rendering (SSR)?

The `createCallable` and `Root` components support SSR. However, the `call()` method itself is client-only, as it depends on user interaction in the browser.

Found this useful? Share it.

One short daily email of tools worth shipping. No drip funnel.

one email a day · unsubscribe in two clicks · no third-party tracking

🚀Discover More

Stay Ahead of the AI Curve

Discover the best AI tools, agents, and MCP servers curated by Stork.AI. Find the right solutions to supercharge your workflow.

P.S. Built something worth using? List it on Stork