eBay / nice-modal-react

A modal state manager for React.
https://ebay.github.io/nice-modal-react
MIT License
1.96k stars 110 forks source link

How to avoid multiple triggers when modal.keepMounted is true #35

Closed ficapy closed 2 years ago

ficapy commented 2 years ago

Thanks a lot for such a great library that makes the code better split!

I wanted to keep the user's temporary input and found that modal.keepMounted = true would do it

but this will cause the callback function to be triggered multiple times on the last submit, and I want it to be called only once at the end.

code Link

supnate commented 2 years ago

You are welcome @ficapy !

I can't reproduce the issue. When I click submit only one log message in the console.

BTW, we usually use code like below to set keepMounted:

const MyModal = useModal(MyAntdModal, { keepMounted: true });
ficapy commented 2 years ago

@supnate Hello, I recorded a video https://www.loom.com/share/8898a1e16af94ca4b579222648f391a8

import { Modal, Button, Form } from "antd";
import FormBuilder from "antd-form-builder";
import NiceModal, { useModal, antdModal } from "@ebay/nice-modal-react";

const MyAntdModal = NiceModal.create(() => {
  const modal = useModal();
  const [form] = Form.useForm();

  const handleSubmit = async () => {
    await form.validateFields();
    const val = form.getFieldsValue();
    modal.resolve(val);
  };
  const meta = [{ key: "name", label: "Name", required: true }];
  return (
    <Modal title="Hello Antd" {...antdModal(modal)} onOk={handleSubmit}>
      <Form form={form}>
        <FormBuilder meta={meta} form={form} />
      </Form>
    </Modal>
  );
});

export default function App() {
  const MyModal = useModal(MyAntdModal, { keepMounted: true });
  const handleOk = async () => {
    const val = await MyModal.show();
    // output multiple times
    console.log(val);
    await MyModal.hide();
  };
  return (
    <Button type="primary" onClick={handleOk}>
      Show Modal
    </Button>
  );
}
ficapy commented 2 years ago

I read the source code and the cause is similar to the following code, how do I avoid triggering then multiple times?

let theResolve 
const a = new Promise((resolve) => {
    theResolve = resolve
})
a.then((v) => {console.log(v)})
a.then((v) => {console.log(v)})
a.then((v) => {console.log(v)})

theResolve('hello')
ficapy commented 2 years ago

I am a newbie in front-end

I found that it can be solved by the following method, which may be very dirty

add removeCallbacks function

export const removeCallbacks = (modalId: string): void => {
  delete modalCallbacks[modalId];
  delete hideModalCallbacks[modalId];
};

and

afterClose: () => {
      // Need to resolve before remove
      modal.resolveHide();
      if (!modal.keepMounted) {
        modal.remove();
      } else {
        modal.removeCallbacks();
      }
    }
supnate commented 2 years ago

I got it! Thanks for the detailed description. I will look at it soon.

supnate commented 2 years ago

Fixed, plz update to v1.2.1. Thanks again for reporting it!