基于Promise的React确认模态框取消后二次确认失效求助
问题:React Final Form中确认模态框取消后无法再次触发保存逻辑
问题现象
用户首次打开模态框并点击确认可正常执行后续保存逻辑;但用户取消一次后,再次打开模态框并点击确认时,无法触发后续保存操作。
问题根源
Promise状态一旦变为rejected(用户首次取消),后续即使调用resolveConfirm,状态也不会改变,导致二次确认时await仍返回rejected,终止逻辑执行。要求在**不重新渲染组件(避免丢失表单已选值)**的前提下解决。
现有代码
Campaign组件
function Campaign() { let resolveConfirm; let rejectConfirm; const confirmPromise = new Promise((resolve, reject) => { resolveConfirm = resolve; rejectConfirm = reject; }); const modal = ( <ConfirmModal name={MODAL_DISABLE_SOCIAL_CAMPAIGNS} title={t('Confirm Uncheck')} buttonText={t('Confirm')} onConfirm={resolveConfirm} modalEvents={{ onClose: () => { try { rejectConfirm(); } catch (e) {} }, }} > <p>{t('Are you sure you want to disable ?')}</p> </ConfirmModal> ); return ( <OpenModal modal={modal}> {(open) => ( <ManageForm openConfirmModal={({ campaign }, form) => { const isUnchecked = !campaign?.selected; // 仅取消选中复选框时才打开确认弹窗 if (isUnchecked) { open(); return confirmPromise; } return false; }} > {(params) => {... }} </ManageForm> )} </OpenModal> ) }
ManageForm组件
import { Form } from 'react-final-form'; import Button from 'components/UI/Button'; function ManageForm(props){ const { openConfirmModal } = props; // 点击保存按钮时执行 const handleSubmit = async (formValues, form) => { if (openConfirmModal) { const openPromise = openConfirmModal(formValues, form); if (openPromise) { try { await openPromise; } catch (e) { // 用户取消则终止后续逻辑 return; } } } // 仅当弹窗确认成功后才执行后续网络请求 const response = await saveEndpoint({ ...formValues }); } return ( <Form onSubmit={handleSubmit}> {(formProps) => ( <form> .... <Button label={t('button_label.save')} type="submit" appearance="brand" /> .... </form> )} </Form> ); }
解决方案
核心思路是每次触发模态框时创建新的Promise,而非复用同一个已进入终态的Promise。通过useRef存储当前模态框对应的resolve/reject函数,既不会触发组件重新渲染,又能保证每次交互的独立性。
修改后的Campaign组件代码
import React from 'react'; function Campaign() { // 用ref存储当前弹窗的resolve/reject函数,避免组件重渲染且不会丢失引用 const confirmRef = React.useRef({ resolve: null, reject: null }); const modal = ( <ConfirmModal name={MODAL_DISABLE_SOCIAL_CAMPAIGNS} title={t('Confirm Uncheck')} buttonText={t('Confirm')} onConfirm={() => { if (confirmRef.current.resolve) { confirmRef.current.resolve(); // 执行后重置ref,避免内存泄漏 confirmRef.current = { resolve: null, reject: null }; } }} modalEvents={{ onClose: () => { if (confirmRef.current.reject) { confirmRef.current.reject(); // 执行后重置ref confirmRef.current = { resolve: null, reject: null }; } }, }} > <p>{t('Are you sure you want to disable ?')}</p> </ConfirmModal> ); return ( <OpenModal modal={modal}> {(open) => ( <ManageForm openConfirmModal={({ campaign }, form) => { const isUnchecked = !campaign?.selected; if (!isUnchecked) return false; open(); // 每次打开弹窗都创建新的Promise,并将resolve/reject存入ref return new Promise((resolve, reject) => { confirmRef.current = { resolve, reject }; }); }} > {(params) => {...}} </ManageForm> )} </OpenModal> ) }
方案说明
- 用
useRef存储当前弹窗的resolve和reject函数,不会触发组件重新渲染,符合不丢失表单值的要求。 - 每次调用
openConfirmModal时生成新的Promise,确保每次弹窗交互都是独立的实例,不会复用已进入终态的Promise。 - 弹窗的确认/关闭事件通过ref调用对应的resolve/reject,并在执行后重置ref,避免内存泄漏。
修改后,无论用户取消多少次,再次打开弹窗时都会生成新的Promise,确认后能正常触发后续保存逻辑,同时表单值不会丢失。
内容的提问来源于stack exchange,提问作者Dev9999
相关产品推荐
相关产品推荐

