You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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>
  )
}

方案说明

  1. 用useRef存储当前弹窗的resolve和reject函数,不会触发组件重新渲染,符合不丢失表单值的要求。
  2. 每次调用openConfirmModal时生成新的Promise,确保每次弹窗交互都是独立的实例,不会复用已进入终态的Promise。
  3. 弹窗的确认/关闭事件通过ref调用对应的resolve/reject,并在执行后重置ref,避免内存泄漏。

修改后,无论用户取消多少次,再次打开弹窗时都会生成新的Promise,确认后能正常触发后续保存逻辑,同时表单值不会丢失。

内容的提问来源于stack exchange,提问作者Dev9999

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 19:15:49