Irbisa · Cheatsheet
Routing
React Router v7, nested routes and layouts, params and search params, loaders and actions, protected routes, code splitting by route
What is client-side routing, and how does it differ from traditional server navigation?
How do you set up routing in React Router v7, and what are its three modes?
import { createBrowserRouter, RouterProvider } from 'react-router';import { createRoot } from 'react-dom/client'; const router = createBrowserRouter([ { path: '/',…What is the difference between
<Link>,<NavLink>anduseNavigate, and why not use a plain<a href>?import { Link, NavLink, useNavigate } from 'react-router'; export function Nav() { return ( <nav> <Link to="/">Home</Link>…How do nested routes and layouts work in React Router, and what does
<Outlet>do?const router = createBrowserRouter([ { path: '/projects/:projectId', Component: ProjectLayout, children: [ { index: true, Component: Overview }, // /projects/7…How do you define and read dynamic URL params in React Router?
import { useParams } from 'react-router'; // route: { path: 'users/:userId', Component: UserPage }export function UserPage() { const { userId } = useParams<{ userId: string }>(); const id = Number(userId);…What is the difference between browser, hash and memory routers, and why does a refreshed deep link return 404 on static hosting?
How do you read and update search params with
useSearchParams?import { useSearchParams } from 'react-router'; export function ProductSearch() { const [params, setParams] = useSearchParams(); const q = params.get('q') ?? ''; const page = Math.max(1, Number(params.get('page')) || 1);…Find the bug: choosing a sort order wipes the search query and the page number from the URL.
function SortSelect() { const [params, setParams] = useSearchParams(); return ( <select value={params.get('sort') ?? 'new'} onChange={(e) => setParams({ sort: e.target.value })} > <option value="new">Newest</option> <option value="price">Price</option> </select> );}What are loaders in React Router, and how are they better than fetching data in
useEffect?import { createBrowserRouter, useLoaderData, type LoaderFunctionArgs } from 'react-router'; async function userLoader({ params, request }: LoaderFunctionArgs) { const res = await fetch(`/api/users/${params.userId}`, { signal: request.signal }); if (!res.ok) throw new Response('Not found', { status: 404 }); return (await res.json()) as User;…What are actions and
<Form>in React Router, and what happens after a submission?import { Form, redirect, useActionData, useNavigation, type ActionFunctionArgs } from 'react-router'; export async function action({ request }: ActionFunctionArgs) { const form = await request.formData(); const title = String(form.get('title') ?? '').trim(); if (!title) return { error: 'Title is required' };…Find the bug: going from
/users/1/editto/users/2/editupdates the URL, but the form still shows user 1's name and email.// route: { path: 'users/:userId/edit', loader: userLoader, Component: EditUser }export function EditUser() { const user = useLoaderData<typeof userLoader>(); const [name, setName] = useState(user.name); const [email, setEmail] = useState(user.email); return ( <form> <input value={name} onChange={(e) => setName(e.target.value)} /> <input value={email} onChange={(e) => setEmail(e.target.value)} /> </form> );}How do you implement protected routes in React Router?
import { createBrowserRouter, redirect, type LoaderFunctionArgs } from 'react-router'; async function requireUser({ request }: LoaderFunctionArgs) { const user = await getSession(); if (!user) { const next = new URL(request.url).pathname;…Find the bug: the account page flashes on screen for a moment before a signed-out user is redirected to login.
export function RequireAuth() { const { user } = useSession(); const navigate = useNavigate(); useEffect(() => { if (!user) navigate('/login'); }, [user, navigate]); return <Outlet />;}How do you warn the user before leaving a page with unsaved changes in React Router?
import { useEffect, useState } from 'react';import { useBlocker } from 'react-router'; export function useUnsavedChangesGuard(isDirty: boolean) { // in-app navigation: links, navigate(), Back and Forward const blocker = useBlocker(…How do you code-split by route in React Router?
import { createBrowserRouter } from 'react-router'; export const router = createBrowserRouter([ { path: '/', Component: Home }, // stays in the main bundle { path: 'reports/:id',…How do you handle errors and 404 pages in React Router?
import { data, isRouteErrorResponse, useRouteError, type LoaderFunctionArgs } from 'react-router'; export async function loader({ params }: LoaderFunctionArgs) { const post = await getPost(params.slug!); if (!post) throw data('Post not found', { status: 404 }); return post;…How do you show pending UI during navigation, and how do you keep a slow loader from blocking the page?
import { Suspense } from 'react';import { Await, useLoaderData, useNavigation, type LoaderFunctionArgs } from 'react-router'; export async function loader({ params }: LoaderFunctionArgs) { const comments = getComments(params.id!); // not awaited: streamed later const post = await getPost(params.id!); // awaited: the navigation waits for it…Why does a new page sometimes open scrolled halfway down after a client-side navigation, and how does
<ScrollRestoration>fix it?import { Link, Outlet, ScrollRestoration } from 'react-router'; export function Root() { return ( <> <Header />…What changed in React Router v7 compared with v6, and how do you migrate?
What happens to in-flight loaders when the user navigates again, and how does React Router decide what to revalidate?
import type { LoaderFunctionArgs, ShouldRevalidateFunctionArgs } from 'react-router'; export async function loader({ params, request }: LoaderFunctionArgs) { // aborted automatically if the user navigates away before it finishes const res = await fetch(`/api/projects/${params.id}/sidebar`, { signal: request.signal }); if (!res.ok) throw new Response('Failed to load', { status: res.status });…What does React Router framework mode add, and when would you choose it over data mode or Next.js?
// app/routes/product.tsximport type { Route } from './+types/product'; export async function loader({ params }: Route.LoaderArgs) { // runs only on the server: the database client never ships to the browser const product = await db.product.findUnique({ where: { id: params.id } });…