How to Use Fetcher in Remix for Data Mutations and Fetching
In Remix, you use the
useFetcher hook to perform data mutations or fetch data without changing routes. It provides a fetcher object that lets you submit forms or load data programmatically, keeping your UI in sync without full page reloads.Syntax
The useFetcher hook returns a fetcher object with methods and state to handle form submissions and data loading.
fetcher.Form: A form component that submits data using fetcher.fetcher.submit(data, options): Programmatically submit data.fetcher.load(url): Load data from a URL without navigation.fetcher.data: Holds the response data from the action or loader.fetcher.state: Represents the fetcher's current state like "idle" or "submitting".
jsx
import { useFetcher } from "@remix-run/react"; function MyComponent() { const fetcher = useFetcher(); // Using fetcher.Form to submit data return ( <fetcher.Form method="post" action="/some-action"> <input name="name" /> <button type="submit">Submit</button> </fetcher.Form> ); }
Example
This example shows how to use useFetcher to submit a form without navigating away and display the response message.
jsx
import { useFetcher } from "@remix-run/react"; export default function ContactForm() { const fetcher = useFetcher(); return ( <div> <fetcher.Form method="post" action="/contact"> <label htmlFor="email">Email:</label> <input id="email" name="email" type="email" required /> <button type="submit" disabled={fetcher.state === "submitting"}> {fetcher.state === "submitting" ? "Sending..." : "Send"} </button> </fetcher.Form> {fetcher.data?.message && <p>{fetcher.data.message}</p>} </div> ); }
Output
<form> with email input and submit button; after submit, shows response message below the form
Common Pitfalls
- Not using
fetcher.Formorfetcher.submitcauses full page reloads instead of smooth fetcher behavior. - Forgetting to handle
fetcher.datato update UI after submission. - Using
method="get"withfetcher.Formexpecting mutations; usepostor other methods for actions. - Not disabling submit button during
fetcher.state === "submitting"can cause duplicate submissions.
jsx
/* Wrong way: normal form causes full page reload */ function Wrong() { return ( <form method="post" action="/some-action"> <input name="name" /> <button type="submit">Submit</button> </form> ); } /* Right way: use fetcher.Form for smooth submission */ import { useFetcher } from "@remix-run/react"; function Right() { const fetcher = useFetcher(); return ( <fetcher.Form method="post" action="/some-action"> <input name="name" /> <button type="submit" disabled={fetcher.state === "submitting"}> Submit </button> </fetcher.Form> ); }
Quick Reference
| Fetcher API | Description |
|---|---|
| useFetcher() | Returns the fetcher object to manage form submissions and data loading. |
| fetcher.Form | Form component that submits data without page reload. |
| fetcher.submit(data, options) | Programmatically submit data to an action. |
| fetcher.load(url) | Load data from a loader without navigation. |
| fetcher.data | Response data from the last submission or load. |
| fetcher.state | Current state: 'idle', 'submitting', or 'loading'. |
Key Takeaways
Use
useFetcher to submit forms or load data without changing routes.Wrap forms with
fetcher.Form to avoid full page reloads.Check
fetcher.state to handle loading states and disable buttons.Access
fetcher.data to update UI after submissions or loads.Avoid normal
<form> tags for mutations when using Remix fetcher.