How best to prevent double button clicks and duplicate / parallel mutations #10041
Replies: 3 comments 6 replies
-
|
Does this differ from when you have a flag in local state that you set when the button is clicked? Because the component should re-render immediately with |
Beta Was this translation helpful? Give feedback.
-
|
There are two separate things happening here. TkDodo's point about The A ref doesn't have the stale closure problem. Every closure captures the same ref object, so reading const mutatingRef = useRef(false);
const onSubmit = handleSubmit(async (data) => {
if (mutatingRef.current) return;
mutatingRef.current = true;
try {
await mutation.mutateAsync({ arg: 'value' });
} finally {
mutatingRef.current = false;
}
});The Keep |
Beta Was this translation helpful? Give feedback.
-
|
Re-renders are async, but React 18 flushes synchronously after browser event handlers, so the button IS disabled before a normal second click is dispatched. The failure case is double-clicks within a single frame, where both events queue before any flush runs. The ref guard does not compensate for slow renders. It's the right primitive when you need guard semantics outside React's render cycle. Conflating the two weakens the case for a built-in solution. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Sometimes we find users are able to accidentally double click a button and kick off duplicate / parallel mutations.
We disable the button when
mutation.isPendingistruebut that isn't set immediately on mutate so there is a short time window when it's possible to double click the button and kick off extra mutations.Wondering if others experience this and if anyone has adopted a clean workaround? Or do folks live with the race condition?
Thanks!
Our buttons look like this:
And our event handlers looks like this:
Beta Was this translation helpful? Give feedback.
All reactions