🪟 Windows TippsGrok for PC: Using xAI’s Chat Assistant On a Bigger Screen(16.09.2026 um 09:33 Uhr)
🪟 Windows TippsWindows 11 26H2: Release, Neuerungen und wer jetzt handeln muss(16.09.2026 um 09:37 Uhr)
🪟 Windows TippsGoogle Chrome(16.09.2026 um 08:30 Uhr)
🪟 Windows TippsGoogle stopft mehrere kritische Chrome-Lücken(16.09.2026 um 09:24 Uhr)
🪟 Windows TippsKI-Power für eine klare Sprache(16.09.2026 um 08:45 Uhr)
🤖 Android TippsDas Ende einer Ära: Samsung-Nutzer müssen sich umstellen(16.09.2026 um 08:25 Uhr)
🪟 Windows TippsGrok for PC: Using xAI’s Chat Assistant On a Bigger Screen(16.09.2026 um 09:33 Uhr)
🪟 Windows TippsWindows 11 26H2: Release, Neuerungen und wer jetzt handeln muss(16.09.2026 um 09:37 Uhr)
🪟 Windows TippsGoogle Chrome(16.09.2026 um 08:30 Uhr)
🪟 Windows TippsGoogle stopft mehrere kritische Chrome-Lücken(16.09.2026 um 09:24 Uhr)
🪟 Windows TippsKI-Power für eine klare Sprache(16.09.2026 um 08:45 Uhr)
🤖 Android TippsDas Ende einer Ära: Samsung-Nutzer müssen sich umstellen(16.09.2026 um 08:25 Uhr)

🔧 Programmierung 🕛 vor 2 Jahren 5 Min Lesezeit
0

Validated forms with useFetcher in Remix

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Build a custom "useFetcherForm" hook to easily handle fetcher requests.




Interacting with the server without using window.navigation significantly improves the user experience. E.g: Login forms within a dialog box or modal, optimistic UI forms or submitting multiple forms within a complex view.



If you are not familiar with Remix or the useFetcher hook, please refer to:










The FetcherForm Provider



The Remix fetcher object contains three primary attributes: fetcher.state, fetcher.data and the method fetcher.submit. To interact with them we will use React.useEffect.



This post will show how to create a provider that manages the state of a fetcher submitted form, along with a minimal custom hook:




CODE
const { onChange, submitForm, isSubmitted, error } = useFetcherForm();






Let's break down the FetcherFormProvider props one by one.



onChange



External inputs will notify through this method to change the internal state of the provider, it receives a FormData argument:




CODE
export default function FetcherFormProvider({
action,
method,
children,
}: {
action: string;
method: SubmitOptions['method'];
children: React.ReactNode;
}) {
const [formData, setFormData] = useState<FormData>();
[...]
return (
<FetcherFormContext.Provider
value={[
(formData: FormData) => {
setFormData(formData);
},
[...]
]}
>
{children}
</FetcherFormContext.Provider>
);
}






submitForm



Since the formData was already captured by the onChange method, the request can be send by calling fetcher.submit:




CODE
export default function FetcherFormProvider({
action,
method,
children,
}: {
action: string;
method: SubmitOptions['method'];
children: React.ReactNode;
}) {
const fetcher = useFetcher();
const [formData, setFormData] = useState<FormData>();

[...]
return (
<FetcherFormContext.Provider
value={[
(formData: FormData) => {
setFormData(formData);
},
() => {
if (formData) {
fetcher.submit(formData, {
method,
action,
});
}
},
[...]
]}
>
{children}
</FetcherFormContext.Provider>
);
}






isSubmitted



Submitting the form is an asynchronous operation. There is a separate variable to listen to the form submitted event: isSubmitted. This is helpful in the following cases:




  1. To close the Dialog or Modal when the form is successfully submitted.

  2. To check from outside that the form was submitted and/or the request returned an OK status.




CODE
export default function FetcherFormProvider({
action,
method,
children,
}: {
action: string;
method: SubmitOptions['method'];
children: React.ReactNode;
}) {
const fetcher = useFetcher();

+ const [isSubmitted, setIsSubmitted] = useState(false);
[...]
const [formData, setFormData] = useState<FormData>();

useEffect(() => {
const response = fetcher.data as { error: string } | undefined;

+ if (isSubmitted || error) return;

if (fetcher.state === 'loading' && response) {
[...]
+ setIsSubmitted(true);
}
}, [fetcher, action, formData, isSubmitted, error]);

return (
<FetcherFormContext.Provider
value={[
(formData: FormData) => {
setFormData(formData);
},
() => {
if (formData) {
fetcher.submit(formData, {
method,
action,
});
}
},
+ isSubmitted,
[...]
]}
>
{children}
</FetcherFormContext.Provider>
);
}






error



One drawback of using Remix useFetcher is the lack of a straightforward error handling method. There are proposals in progress to provide a more streamlined error handling approach:







As a workaround we can rely on fetcher.state to check if the request is complete and get the message with fetcher.data by defining a common structure between the client and server actions.



The highlights



const response = fetcher.data as { error: string } | undefined; -> defines the JSON response structure to be received form the server return json({ error: new Error() }, { status: 400 } );



if (fetcher.state === 'loading' && response) { -> checks if the request is completed and a response is available.




CODE
export default function FetcherFormProvider({
action,
method,
children,
}: {
action: string;
method: SubmitOptions['method'];
children: React.ReactNode;
}) {
const fetcher = useFetcher();

const [isSubmitted, setIsSubmitted] = useState(false);
+ const [error, setError] = useState<string>();

const [formData, setFormData] = useState<FormData>();

useEffect(() => {
const response = fetcher.data as { error: string } | undefined;

if (isSubmitted || error) return;

if (fetcher.state === 'loading' && response) {
+ if (response.error) {
+ setError(response.error);
+ return;
+ }
setIsSubmitted(true);
}
}, [fetcher, action, formData, isSubmitted, error]);

return (
<FetcherFormContext.Provider
value={[
(formData: FormData) => {
setFormData(formData);
+ setError(undefined);
},
() => {
if (formData) {
fetcher.submit(formData, {
method,
action,
});
}
},
isSubmitted,
+ error,
]}
>
{children}
</FetcherFormContext.Provider>
);
}






Optionally, the error state management can be sent as a callback. This can be received in the onSubmit function and registered as state. For example, using a registeredCallback:




CODE
- if (response.error) {
- setError(response.error);
- return;
- }
+ registeredCallback?.(response.error);









The useFetcherForm hook



The values sent to FetcherFormContext.Provider are defined in the FetcherFormContext




CODE
const FetcherFormContext = createContext<
[(formData: FormData) => void, (callback?: () => void) => void, boolean, string?]
>([() => null, () => null, false]);






Then the hook exposes them in an object structure:




CODE
export const useFetcherForm = () => {
const [onChange, submitForm, isSubmitted, error] = useContext(FetcherFormContext);
return {
onChange,
submitForm,
isSubmitted,
error,
};
};






An example of how it can be defined:




CODE
export function AssignmentUpdateStatusDialogButton({
assignmentId,
status,
}: {
assignmentId: string;
status: AssignmentStatus;
}) {
const [isAttached, setIsAttached] = useState(false);
const dialog = useRef<HTMLDialogElement>();

useEffect(() => {
if (isAttached) {
dialog.current?.showModal();
}
}, [isAttached, dialog]);

return (
<ClientOnly>
{() => (
<>
{isAttached &&
createPortal(
<FetcherFormProvider
action={`/assignments/${assignmentId}/status`}
method="post"
>
<AssignmentUpdateStatusDialog
ref={dialog}
[...]
setIsAttached={setIsAttached}
/>
</FetcherFormProvider>,
document.body
)}
<button
type="button"
className="cursor-pointer leading-none"
onClick={() => setIsAttached(true)}
>
<AssignmentStatusBadge status={status} />
</button>
</>
)}
</ClientOnly>
);
}


Vollständiger Original-Artikel
Den kompletten Beitrag mit allen Details direkt auf dev.to lesen.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Grok for PC: Using xAI’s Chat Assistant On a Bigger Screen
1 Quelle
Windows 11 26H2: Release, Neuerungen und wer jetzt handeln muss
1 Quelle
WMF-Messerblock mit 7 Teilen kostet bei Amazon aktuell deutlich weniger
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Validated forms with useFetcher in Remix

Thematisch verwandte Begriffe: Validated, forms, with, useFetcher · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...