Thinking In Web State With React Router 7

2025-09-20T18:48:00.000Z
17 views

Remix is Dead, Long Live Remix!

/blogs/web-state-with-react-router-7/server-state-usefetcher

Server As State: useFetcher()

useFetcher() is a hook for interacting with loaders and actions without navigating, changing the URL or affecting browser history. It can be used as a component (like <Form>), or it can be used directly through one of its built in methods.


The biggest benefits of useFetcher() is that it allows you to read or write data without causing URL changes or navigations. It's perfect for small interactions that shouldn't be bookmarkable or shareable, that dont need full-page revalidations, or when you need to make multiple isolated requests on the same page.


We'll illustrate these benefits in the following example by using both the component and method forms of useFetcher() to simulate liking and favoriting movies.


function MovieCard({initial}: {initial: Movie}) {
    const fetcher = useFetcher();
    const current = fetcher.data?.movie ?? initial;
    const pendingIntent = fetcher.state === "submitting" ? String(fetcher.formData?.get("intent")) : null;

    let likes = current.likes;
    let reaction = current.reaction;
    let starred = current.starred;

    if (pendingIntent === "toggleStar") {
        starred = !current.starred;
    } else if (pendingIntent === "toggleLike") {
        if (reaction === "like") {
            likes -= 1;
            reaction = null;
        } else {
            likes += 1;
            reaction = "like";    
        }
    }

    return(
        <div>
            <Image />
            <Star onClick={() => fetcher.submit({intent: "toggleStar", movieId: initial.id}, {method: "post"})} isStarred={starred} />
            <div>
                <LikeCount count={likes} />
                <fetcher.Form method="post">
                    <input type="hidden" name="intent" value="toggleLike" />
                    <input type="hidden" name="movieId" value={initial.id} />

                    <button type="button" title={reaction === "like" ? "Unlike" : "Like"}>
                        <ThumbsUp isLiked={reaction === "like"} />
                    </button>
                </fetcher.Form>
            </div>
        </div>
    );
}

Movies

10
1993
Jurassic Park
20
2014
Interstellar
30
2010
Inception
3
2007
The Man From Earth
35
2011
Rise Of The Planet Of The Apes
40
1979
Alien
50
2017
Blade Runner 2049
25
2018
Annihilation
15
1997
Contact
45
1997
Gattaca

RICKY
KISSOON