new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

React Router · API · all subjects

form & navigation

5 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

URL search params for storing UI view state

Instead of managing view state in React state and manually synchronizing with the URL, you can read and set state directly in the URL using HTML forms with useSearchParams. Use Form component with button elements that set URL parameters through form submission, which automatically updates searchParams without requiring manual state synchronization.

Form validation simplification with actionData

Instead of managing validation errors in React state, perform validation server-side in the action and return errors via actionData. In the component, access validation errors directly from actionData (e.g., actionData?.errors?.userName) and use useNavigation to determine if the form is submitting (e.g., navigation.formAction === "/signup"). This eliminates the need for multiple React state declarations and change event listeners.

Form component with Form from react-router

Use the Form component from react-router instead of standard HTML form for automatic network state handling. The Form component works with actions, provides automatic submission handling, and the form is functional even before JavaScript loads (progressive enhancement).

Server-side validation with actionData pattern

Perform form validation server-side in the action function. If validation fails, return an object with errors field containing validation errors. The component receives this via actionData and displays errors. This eliminates client-side validation duplication and leverages server information that only the server has access to (like checking for duplicate usernames).

Navigation blocking example with form

Complete working example showing navigation blocking with useBlocker and useFetcher. User fills out a contact form, navigation is blocked while form is dirty, confirmation UI appears with Leave and Stay here buttons, and blocker is reset when form action resolves: import { useFetcher, useBlocker } from "react-router"; import { useState, useCallback, useEffect, useRef } from "react"; import type { Route } from "./+types/contact"; export async function action({ request }: Route.ActionArgs) { let formData = await request.formData(); let email = formData.get("email"); let message = formData.get("message"); console.log(email, message); return { ok: true }; } export default function Contact() { let [isDirty, setIsDirty] = useState(false); let fetcher = useFetcher(); let formRef = useRef<HTMLFormElement>(null); let blocker = useBlocker( useCallback(() => isDirty, [isDirty]), ); useEffect(() => { if (fetcher.data?.ok) { formRef.current?.reset(); if (blocker.state === "blocked") { blocker.proceed(); } } }, [fetcher.data]); return ( <fetcher.Form ref={formRef} method="post" onChange={(event) => { let email = event.currentTarget.email.value; let message = event.currentTarget.message.value; setIsDirty(Boolean(email || message)); }} > <p> <label> Email: <input name="email" type="email" /> </label> </p> <p> <textarea name="message" /> </p> <p> <button type="submit"> {fetcher.state === "idle" ? "Send" : "Sending..."} </button> </p> {blocker.state === "blocked" && ( <div> <p>Wait! You didn't send the message yet:</p> <p> <button type="button" onClick={() => blocker.proceed()} > Leave </button>{" "} <button type="button" onClick={() => blocker.reset()} > Stay here </button> </p> </div> )} </fetcher.Form> ); }

Give your agent this brain