Promisifying Modal Dialogs Ends State Bloat and Fragmented Business Logic
Modal-heavy enterprise React apps accumulate brittle state management that makes serial workflows hard to read and harder to change. Promisifying modals collapses scattered visible booleans and callbacks into linear async functions, cutting the maintenance cost of multi-step user interactions.
Enterprise React applications often accumulate dozens of modal dialogs, each managed by its own visible boolean, open/close handlers, and scattered callback logic. When modals chain together—open A, confirm, open B, confirm, refresh—the business flow fragments across components and files. render-promise collapses this into a single pattern: call openXxxModal() and await the result. Confirmation resolves the Promise; cancellation rejects it.
The mechanism is a thin wrapper over imperative React rendering. It creates a DOM container, renders the modal component into it, and destroys both on close. This guarantees state is cleaned up on every close, unlike the visible=false approach that leaves stale internal state. The library also normalizes onOk payloads so a single parameter, multiple parameters, or no parameters all resolve cleanly.
Adopting this pattern means pages no longer pre-mount modals in JSX, effects fire only when a modal actually opens, and complex workflows read top-to-bottom as sequential await expressions. The same abstraction works for any dismissable UI surface—confirmation toasts, slide-out panels, fixed-position prompts—not just Ant Design modals.
The core insight is not technical but conceptual: a modal is a user decision point, and a decision maps cleanly onto Promise resolve/reject semantics.
Ant Design's own confirm, message, and notification APIs already use imperative rendering under the hood; render-promise extends that pattern to arbitrary components.
The idempotent cleanup switch—ensuring destroy logic runs exactly once even if called multiple times—is the small detail that prevents memory leaks in long-running SPAs.
Type inference that maps onOk's parameters directly to the resolved Promise value removes a common friction point where developers manually cast modal results.
Pre-mounting modals with visible=false causes useEffect to fire on page load, triggering unnecessary API calls; lazy instantiation fixes this by design.
Codebases that adopt this pattern tend to see modal-related state variables drop to zero in page components, which simplifies the component's public API.