Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue: event.stopPropagation() does not work in callback passed to handleSubmit #916

Open
1 task done
c-t-k opened this issue Feb 28, 2023 · 12 comments
Open
1 task done
Labels
question Further information is requested

Comments

@c-t-k
Copy link

c-t-k commented Feb 28, 2023

Version Number

7.43.2

Codesandbox/Expo snack

https://codesandbox.io/s/snowy-https-hnyckh?file=/src/App.tsx

Steps to reproduce

  1. Go to https://codesandbox.io/s/snowy-https-hnyckh?file=/src/App.tsx
  2. Click on 'Show modal'
  3. Enter an e-mail address in the modal form
  4. Click the 'Submit' button on the modal
  5. Observe that the outer form submit count increases and its onSubmit handler is called.

Expected behaviour

The outer form should not be submitted as the Modal component calls event.stopPropagation() in the callback passed to handleSubmit.

What browsers are you seeing the problem on?

Chrome

Relevant log output

in <Modal /> onSubmit: 
{email: "foo@example.com"}
in top form onSubmit: 
{email: "", firstName: ""}

Code of Conduct

  • I agree to follow this project's Code of Conduct
@c-t-k
Copy link
Author

c-t-k commented Feb 28, 2023

From looking at the source in createFormControl.ts this seems to be because the onValid callback is called after an await point: https://github.com/react-hook-form/react-hook-form/blob/f4577b7d79810b6631d4f665ae7acbea5c90d00f/src/logic/createFormControl.ts#L1055

So the onSubmit handler will be suspended before it reaches the stopPropagation() call (and presumably since react doesn't await on async event handlers, the control flow to bubble up the event still occurs). I couldn't find any documentation on the react-hook-form site covering this behavior, but apologies if I overlooked something.

@bluebill1049
Copy link
Member

bluebill1049 commented Feb 28, 2023

hey, @c-t-k we do support async callback within the handleSubmit, eg post a request. It's async by default. I will fix the type description in the doc.

@bluebill1049 bluebill1049 added the question Further information is requested label Feb 28, 2023
@c-t-k
Copy link
Author

c-t-k commented Feb 28, 2023

hey, @c-t-k we do support async callback within the handleSubmit, eg post a request. It's async by default. I will fix the type description in the doc.

@bluebill1049 I think you might misunderstand me. I understand you can pass an async callback to handleSubmit(), that isn't the issue. It's that calling stopPropagation() on a synthetic event in any callback you pass to handleSubmit() will not work.

See the codesandbox I posted above to see where this is going wrong. The Modal component should prevent a submit event from bubbling up to the top level form, as it uses this as the onSubmit handler on the form it manages:

  const onSubmit = handleSubmit((value, ev) => {
    ev?.stopPropagation();
    onSubmitCallback(value);
    onClose();
  });

However you can see that when the modal's form is submitted, it ends up triggering the outer form despite stopPropagation() being called.

I believe this is because react invokes an onSubmit() handler as though it is a synchronous function, and handleSubmit has an await point in its own code which will cause execution to suspend before the stopPropagation() can be reached (before the onValid() callback you pass is await-ed in the body of handleSubmit().

@bluebill1049
Copy link
Member

bluebill1049 commented Feb 28, 2023

Yes, @c-t-k I understand that, what's your prospered change, I don't think we can remove the await for the onValid callback. can i suggest the following

onSubmit=((e) => {
  // e.
  handleSubmit(() => {})(e)
})

@c-t-k
Copy link
Author

c-t-k commented Feb 28, 2023

@bluebill1049 yeah, this is the workaround I've been using:

<form onSubmit={((e) => {
  e.stopPropagation();
  form.handleSubmit(onSubmitCallback)(e)
})} />

I don't have a proposed fix, it seems to be a problem w/ the design of handleSubmit that it passes the event to onValid and onInvalid though. Since those callbacks can't affect event bubbling at that point, it seems like a design decision that's bound to create surprises. I'd at least suggest making a note about this in your documentation for the time being so that users won't be caught off guard by this behavior.

@bluebill1049 bluebill1049 transferred this issue from react-hook-form/react-hook-form Feb 28, 2023
@bluebill1049
Copy link
Member

https://react-hook-form.com/api/useform/handlesubmit/

Would you like to send us a PR on this? We can describe and move it under the rules section.

@Chandan9898Kumar
Copy link

@c-t-k Could you try this -

{ ev.stopPropagation(); handleSubmit(onSubmit)}} className="outer-form">

@croraf
Copy link

croraf commented Oct 10, 2023

Any progress on this? Might be nice to be able to have a property in useForm hook stopPropagation: boolean?

@Chandan9898Kumar
Copy link

Chandan9898Kumar commented Oct 11, 2023

Hi All, i was working on this issue, this approach is working: if we remove the form from child or simple apply event handler on button itself.

const onSubmit = handleSubmit((value, ev) => {
ev?.preventDefault()
ev?.stopPropagation();
onSubmitCallback(value);
onClose();
});

please let me know if you need more clarity. Thanks

CC - @c-t-k

@Chandan9898Kumar
Copy link

@c-t-k could you please assign this to me.

@Chandan9898Kumar
Copy link

Can someone assign this to me, if it is not resolved

@JayDouglass
Copy link

This is similar to the other answers but I'll post my solution here:

function stopPropagate(callback: (event: FormEvent<HTMLFormElement>) => void) {
  return (e: FormEvent<HTMLFormElement>) => {
    e.stopPropagation();
    callback(e);
  };
}

<form onSubmit={stopPropagate(handleSubmit(onSubmit))}>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants