Skip to content

Commit ca8a75f

Browse files
authored
fix: attach form submit listener before paint to prevent reload flake (#61)
test_form_no_page_reload could fail with render_count == 2 in CI. The Form component attached its submit listener in React.useEffect, which runs *after* the browser paints. That leaves a window after the form is rendered but before the listener is wired, during which a submit falls through to the browser's native GET submission - a full page reload that remounts the app and re-runs the route component, bumping the render counter. Attach the listener in useLayoutEffect instead, which runs synchronously before paint, so the preventDefault handler is always in place by the time the form is visible and interactive. This mirrors the Link preventDefault race addressed for scroll restoration.
1 parent d90b424 commit ca8a75f

1 file changed

Lines changed: 7 additions & 1 deletion

File tree

‎src/js/src/components.ts‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,13 @@ export function Navigate({
133133
* listener for ReactPy-Router's server-side form component.
134134
*/
135135
export function Form({ onSubmitCallback, formClass }: FormProps): null {
136-
React.useEffect(() => {
136+
// Attach the submit listener in a layout effect (before paint) rather than a
137+
// passive effect (after paint). A passive effect leaves a window after the form
138+
// is rendered but before the listener is wired, during which a submit would
139+
// fall through to the browser's native GET submission (a full page reload).
140+
// `useLayoutEffect` runs synchronously before paint, so the listener is always
141+
// in place by the time the form is visible and interactive.
142+
React.useLayoutEffect(() => {
137143
const handleSubmit = (event: Event) => {
138144
event.preventDefault();
139145
const form = event.currentTarget as HTMLFormElement;

0 commit comments

Comments
 (0)