eBay / nice-modal-react

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

FeatureI Idea: Allow developer to update props #2

Closed DaddyWarbucks closed 2 years ago

DaddyWarbucks commented 2 years ago

Thanks for the great library! This is similar to how I have implemented "confirm" modals many times. But this is much more flexible and can be applied to multiple modals, unlike my implementations.

I have found it useful to have some update method available. This allows the developer to update the props of the modal before closing. For example, we may have some disabled and text state and we want to keep the modal open with the button disabled and the text updated before closing. The below example is similar to this: https://github.com/eBay/nice-modal-react#use-modal-with-the-hook

export default NiceModal.create(({ text, disabled, handleOk }) => {
  const modal = useModal();
  return (
    <Modal visible={modal.visible}>
      {text} 
      <Button onClick={handleOk} disabled={disabled}>Confirm</Button>
    </Modal>
  );
});
const modal = useModal(MyConfirmModal);

const handleOk = () => {
  modal.update({ text: 'Deleting...', disabled: true });
  await doTheAsyncDelete();
  modal.close();
};

modal.show({
  text: 'Are you sure you want to delete?',
  disabled: false,
  handleOk
});

I am currently solving this by calling show again and merging the args property.

const modal = useModal(MyConfirmModal);

const handleOk = () => {
  // Note we call show again instead of update
  modal.show({ ...modal.args,  text: 'Deleting...', disabled: true });
  await doTheAsyncDelete();
  modal.close();
};

modal.show({
  text: 'Are you sure you want to delete?',
  disabled: false,
  handleOk
});

Thanks again for the library. I am testing it out in a large app that uses lots of Modals now. Please let me know if calling show({ ...modal.args, disabled: true }) is the right way to handle this. It seems to work when passing the modal in, but I am unsure how it will work when using ids.

supnate commented 2 years ago

Thanks @DaddyWarbucks ! Yes modal.show is designed to be used to update props. You can call it again. It does looks un-natural but if add a update method then we need another method updateAll to remove some props.

BTW, for a confirm modal, besides using onOk you can also consider promise api:

<Modal onOk={() => modal.resolve()} ...

Then you can use then to handle ok:

const modal = useModal(MyConfirmModal);
modal.show({ text: '...' }).then(() => {});
DaddyWarbucks commented 2 years ago

Thanks for the quick reply. That answers my question. I can safely use show again to update props. I am currently using this custom hook.

// TODO: Add some memoization
export const useModal = (ComponentOrId) => {
  const modal = useModalHook(ComponentOrId);
  const update = (props) => modal.show({ ...modal.args, ...props });
  return {
    update,
    ...modal,
  };
};

I like the promise API. But the promise only resolves after hide method has been called, correct?. I want the modal to stay visible (in a disabled/loading state) until after I have done some async action, and then call hide. I noticed a resolve method while poking around in the code. Perhaps something like this will work

modal
  .show({
    text: "Are you sure you want to delete?",
    disabled: false,
  })
  .resolve(async (payload) => {
    modal.update({
      disabled: true,
      text: "Deleting...",
    });

    await doTheAsyncThing();

    modal.hide();

  });
supnate commented 2 years ago

Oh, yes, since you hide the modal out of modal component, promise api seems not proper. However, modal.resolve doesn't hide the modal.