React基于Promise的确认框无法正常工作。一旦用户取消,在后续的确认框打开时,即使用户确认,它也会被取消。

3
我正在使用React Final Form创建表单。我有一个组件,在其中定义了确认模态框和处理它的Promise。函数实现如下所示:
 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 unchecked the selected checkbox only then 
               // confirm dialog box should get open

               if (isUnchecked) {
                open();
                return confirmPromise;
               }
    
               return false;

              }}
>
              {(params) => {...
              }}
            </ManageForm>
          )}
        </OpenModal>
    )
    }

'ManageForm' 组件被导入到上面的 'Campaign' 组件中,并具有一个名为 'save' 的按钮,点击该按钮将调用提交方法并打开确认模态框,其中包括“取消”和“确认”选项。下面是 'ManageForm' 组件的实现:

import { Form } from 'react-final-form';
import Button from 'components/UI/Button';

    function ManageForm(){
     const {
      openConfirmModal
     } = props;
    }
    
    // This runs when clicked on a save button.
    const handleSubmit = (formValues, form) => {
    
           if (openConfirmModal) {
            const openPromise = openConfirmModal(formValues, form);
    
            if (openPromise) {
              try {
                await openPromise;
              } catch (e) {
                // Don't continue if the user cancelled the opening
                return;
              }
            }
          }
          
           // Code after this will run only if openPromise is success.
          // Here a network call happens via saveEndpoint method
          const response = await saveEndpoint({ ...formValues });
    }
      return (
        <Form
         onSubmit={handleSubmit}
        >
        (formProps) => {
         return (
         <form>
           ....
           <Button
             label={t('button_label.save')}
             type="submit"
             appearance="brand"
           />
           ....
         </form>
        )}
    </Form>
  );
}

现在的问题是,当用户第一次取消确认模态框后,如果再次点击保存按钮并再次点击确认,则无法工作。 如果用户第一次登陆页面,然后点击保存按钮,再点击确认按钮,那么它就可以工作。只有在取消一次后,接下来的确认才会失败。
我的发现: 当用户第一次取消时,rejectConfirm被调用,并将confirmPromise设置为rejected,在ManageForm的'openPromise'块中,await openPromise的值会被设置为rejected并停止代码。现在,当用户再次点击保存按钮时,如果用户尝试单击确认,则会调用resolvePromise,但是confirmPromise的值已经被rejectConfirm设置为拒绝(当用户第一次取消时),仍保持不变,即rejected。因此,ManageForm中的await openPromise再次返回拒绝,确认不起作用。
如何处理Promise以使其在第一次取消后继续进行后续的确认调用? 我不能在用户取消确认时重新渲染我的组件,因为这会删除所有已选择的表单值。
谢谢。

1
你能在这里创建一个可工作的示例吗?https://codesandbox.io/s/new?file=/src/App.js 并分享相关链接。这样更容易跟进。 - Charchit Kapoor
嗨@CharchitKapoor:感谢您的回复。我真的想分享工作示例,但实际的代码结构有太多部分,创建它会非常困难。虽然我会尝试在沙盒中获取一些东西。 - Dev9999
1
不要试图创建整个应用程序,只需创建一个示例来说明您的情况。 - Charchit Kapoor
@inwerpsel 你能否请现在看一下上面的代码。做了一些修改。 - Dev9999
https://codesandbox.io/s/new?file=/src/App.js - inwerpsel
显示剩余9条评论
1个回答

1
我明白你在做什么。当你第一次取消确认模态框时,你的承诺值(这里是'confirmPromise')被设置为'rejected'。之后,我假设“Campaign”组件的渲染不会发生,confirmPromise的值保持不变。在随后的确认模态调用中,无论resolveConfirm是否被调用,confirmPromise的值都保持不变。由于这个原因,在组件'ManageForm'中,等待openPromise的值总是被评估为“rejected”,因此它进入catch块并返回,退出handleSubmit函数,进一步的操作也不会发生。这里正在发生的简单建模可以是:jsfiddle.net/utr3Lkp0。
如果您检查上面的fiddle,那么在ManageForm内部,承诺值始终保持为第一次设置的值。
在您的情况下,我所想到的是在'Campaign'组件内设置状态,并在承诺被设置(取消或确认)时更改其值。这将导致'Campaign'组件的重新渲染,并且每次都会有一个新的承诺。如果您担心丢失的初始值,您可以在其他地方单独存储它们,然后在每次渲染后使用它们来初始化表单。

感谢您的回复。我的发现也是一样的。是否有一种方法可以在不设置状态和重新渲染组件“Campaign”的情况下完成。在“确认”调用的情况下,重新渲染会发生,因为在承诺被评估为成功后,会向服务器发出网络调用以发送更新的表单数据,然后组件会被渲染。对于确认模态框的“取消”,我不希望重新渲染。非常感谢@user3760959。 - Dev9999

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接