Irbisa · Шпаргалка
Роутинг
React Router v7, вложенные маршруты и layout, params и search params, loaders и actions, защищённые маршруты, разбиение кода по маршрутам
Что такое клиентский роутинг и чем он отличается от обычной серверной навигации?
Как настроить роутинг в React Router v7 и какие у него есть три режима?
import { createBrowserRouter, RouterProvider } from 'react-router';import { createRoot } from 'react-dom/client'; const router = createBrowserRouter([ { path: '/',…Чем отличаются
<Link>,<NavLink>иuseNavigateи почему не стоит использовать обычный<a href>?import { Link, NavLink, useNavigate } from 'react-router'; export function Nav() { return ( <nav> <Link to="/">Home</Link>…Как в React Router работают вложенные роуты и лейауты и что делает
<Outlet>?const router = createBrowserRouter([ { path: '/projects/:projectId', Component: ProjectLayout, children: [ { index: true, Component: Overview }, // /projects/7…Как в React Router объявить и прочитать динамические параметры URL?
import { useParams } from 'react-router'; // route: { path: 'users/:userId', Component: UserPage }export function UserPage() { const { userId } = useParams<{ userId: string }>(); const id = Number(userId);…Чем отличаются browser-, hash- и memory-роутеры и почему обновлённая глубокая ссылка на статическом хостинге отдаёт 404?
Как читать и обновлять search params через
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);…Найдите баг: выбор сортировки стирает из 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> );}Что такое лоадеры в React Router и чем они лучше загрузки данных в
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;…Что такое экшены и
<Form>в React Router и что происходит после отправки формы?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' };…Найдите баг: при переходе с
/users/1/editна/users/2/editURL меняется, но форма по-прежнему показывает имя и email пользователя 1.// 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> );}Как реализовать защищённые роуты в 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;…Найдите баг: страница аккаунта на мгновение появляется на экране, прежде чем разлогиненного пользователя перенаправит на страницу входа.
export function RequireAuth() { const { user } = useSession(); const navigate = useNavigate(); useEffect(() => { if (!user) navigate('/login'); }, [user, navigate]); return <Outlet />;}Как предупредить пользователя перед уходом со страницы с несохранёнными изменениями в 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(…Как разделить код по роутам в React Router?
import { createBrowserRouter } from 'react-router'; export const router = createBrowserRouter([ { path: '/', Component: Home }, // stays in the main bundle { path: 'reports/:id',…Как обрабатывать ошибки и страницы 404 в 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;…Как показать состояние ожидания при навигации и не дать медленному лоадеру заблокировать страницу?
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…Почему после клиентской навигации новая страница иногда открывается прокрученной до середины, и как это исправляет
<ScrollRestoration>?import { Link, Outlet, ScrollRestoration } from 'react-router'; export function Root() { return ( <> <Header />…Что изменилось в React Router v7 по сравнению с v6 и как мигрировать?
Что происходит с выполняющимися лоадерами, когда пользователь снова переходит на другую страницу, и как React Router решает, что ревалидировать?
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 });…Что добавляет фреймворк-режим React Router и когда выбирать его вместо data-режима или 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 } });…