Введение в React Router 6.4, 4 тыс. слов. Большие изменения: введение Data API. Ты больше не чист!
Введение в React Router 6.4, 4 тыс. слов. Большие изменения: введение Data API. Ты больше не чист!

фон

Каждый раз, когда я открываю официальную документацию React Router, я поражаюсь: API снова изменилось! Давайте посмотрим, какие обновления доступны на этот раз.

хороший парень!Да Я понимаюсерединаиз React Router ?

Когда я разрабатывал «Коллекцию онлайн-настольных игр» в марте 2022 года, я использовал 6.2 версия того времени v6 и v5 v4 По сравнению с API Произошло относительно большое событиеизизменять,但я认可этот些изменять。

Посмотрите это сейчас 6.4 документация по версии, Я хочу пожаловаться. Моя основная точка зрения: Реагировать Router 6.4 Это больше не просто маршрут, он объединяет логику данных.

Ниже этой статьи объективное введение: React Router 6.4 Представляем новые функции Data API и дать в конце Субъективный заключение

1. Новый createXXXXRouter API

1.1 Введение

существовать React Router 6.4 середина,Новый Понятно 3 индивидуальный createXXXXRouter API для поддержки data API:

То есть, да,Если вам не нужен этот 3индивидуальный API,идакартинаv6.0-v6.3Такой же,прямойиспользовать<BrowserRouter>ждать Следующие несколькоиндивидуальныйAPI,Тогда вы не сможете пользоваться API данных.

1.2 createXXXXRouter использование

необходимо объединить<RouterProvider>Вместеиспользовать。можно увидеть,этоиспользоватьодининдивидуальный Конфигурация,Определить маршруты.

Язык кода:jsx
копировать
import * as React from "react";
import * as ReactDOM from "react-dom";
import {
  createBrowserRouter,
  RouterProvider,
} from "react-router-dom";


const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    children: [
      {
        path: "team",
        element: <Team />,
      },
    ],
  },
]);

ReactDOM.createRoot(document.getElementById("root")).render(
  <RouterProvider router={router} />
);

1.3 Вы также можете использовать JSX для определения маршрутов

когда Ран,Если вы предпочитаете определять маршруты с использованием синтаксиса JSX,картина<BrowserRouter>Такой же:

Язык кода:jsx
копировать
<BrowserRouter>
  <Routes>
    <Route index element={<div />} />
  </Routes>
</BrowserRouter>

React Router 6.4 также добавил конфигурацию JSX,ссылкаcreateRoutesFromElements,это有另外одининдивидуальный ИмяcreateRoutesFromChildren

Язык кода:jsx
копировать
const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<Root />}>
      <Route path="dashboard" element={<Dashboard />} />
      <Route path="about" element={<About />} />
    </Route>
  )
);

2. <Route>изизменять

2.1 Что такое API данных?

когдатыиспользоватьcreateXXXXRouterи<RouterProvider>час,Вы можете использовать API данных.

Сказав все это, что такое Data API?

Фактически, да позволяет вам записать «логику получения данных» в определение маршрутизации середина. Каждый раз, когда маршрут там переключается, данные автоматически поступают.

мы начинаем с<Route>изизменять Сразу Может看出,это Новый Понятно3индивидуальный Связанныйизсвойство:

  • loader
  • action
  • errorElement

2.2 <Route> loader свойство

loaderсвойство传入одининдивидуальныйфункция(позволятьда async функция), выполняйте функцию каждый раз перед рендерингом «этот маршрут соответствует элементу». существования「Этот маршрут соответствует изelement」, вы можете использовать hook useLoaderData (будет обсуждаться нижепредставлять)Приходитьполучатьэтотиндивидуальныйфункцияизвозвращаемое значение (обычно это ответ на HTTP-запрос).

Язык кода:jsx
копировать
<Route
  loader={async ({ request }) => {
    // loaders can be async functions
    const res = await fetch("/api/user.json", {
      signal: request.signal,
    });
    const user = await res.json();
    return user;
  }}
  element={<Xxxxxx />}
/>

2.2.1 параметры загрузчика

загрузчиксвойство входящей функции, позволяющей использовать 2индивидуальных параметра:

  • params: еслиRouteсередина Включатьпараметр(Напримерpathда/user/:userId,параметр Сразуда:userId,Вы можете передать params.userId для получения значения параметра маршрута).
  • request: да Web спецификациясередина,Fetch API из Request,代表одининдивидуальныйпросить。Уведомление:этотвнутри指из Нетдатысуществовать loader Внутренняя проблема fetch Запрос выдается в то время, когда пользователь перенаправляется на прежний путь (фактически существующийSingle-Page Приложениесередина, роутер перехватил этот индивидуальный реальный запрос, только многостраничный У Appсередина будет этот индивидуальный запрос) здесь да React Router 6.4 Для удобства разработчиков, когда информация о прежнем пути предоставляется в параметре, они следуют Веб-спецификации,制造Понятноодининдивидуальный Фальшивыйиз запрос. ты можешь пройти request Удобно получать, когда изпараметр предыдущей страницы:
Язык кода:javascript
копировать
<Route
  loader={async ({ request }) => {
    const url = new URL(request.url);
    const searchTerm = url.searchParams.get("q");
    return searchProducts(searchTerm);
  }}
/>

Мне не нужен этот индивидуальный параметр запроса, хорошо? Нет?,因为еслитыиспользоватьwindow.locationполучатьизинформациядакогдапредыдущий последнийизценить,Если пользователь быстро нажимает кнопку,Пусть страница направляется на A,и сразу направиться к B,этотчас候路由AПерепискаRouteизloaderполучатьwindow.locationчас,Можно получить неправильное значение.

Обратите внимание, проходите request,Также есть индивидуальные льготы,это有индивидуальный request.signal, когда пользователь быстро нажимает кнопку, чтобы направить страницу к A и сразу к B. Запрос страницы Aизloader должен быть отменен. Вы можете пройти. signal Реализация следующая:

Язык кода:javascript
копировать
<Route
  loader={async ({ request }) => {
    return fetch("/api/teams.json", {
      signal: request.signal,
    });
  }}
/>

2.2.2 возвращаемое значение загрузчика

функцияизвозвращаемое значение,Сможет существоватьэлементсередина через крючок useLoaderData (См. ниже) Приходите получать. Что вы возвращаете, то и получаете.

но React Router Официальная консультация, возврат к индивидуальному Веб-спецификации серединаиз Fetch API из Response

Вы можете напрямую return fetch(url, config);,Вы также можете составить индивидуальный ответ самостоятельно:

Язык кода:jsx
копировать
function loader({ request, params }) {
  const data = { some: "thing" };
  return new Response(JSON.stringify(data), {
    status: 200,
    headers: {
      "Content-Type": "application/json; utf-8",
    },
  });
}
//...
<Route loader={loader} />

Вы также можете пройти React Router Предоставить из json построить:

Язык кода:jsx
копировать
import { json } from "react-router-dom";

function loader({ request, params }) {
  const data = { some: "thing" };
  return json(data, { status: 200 });
}
//...
<Route loader={loader} />
2.2.2.1 особенныйвозвращаемое значение: redirect

существовать loader , вам может потребоваться перенаправление после проверки, React Router Не рекомендуется вам использовать useNavigation Завершено, рекомендуется существовать непосредственно loader средний прямой return перенаправление, переход на новый URL-адрес.

Язык кода:javascript
копировать
import { redirect } from "react-router-dom";

const loader = async () => {
  const user = await getUser();
  if (!user) {
    return redirect("/login");
  }
};

2.2.3 Исключение, возникающее в загрузчике

Если получить данные не удалось,или другая любая причина,ты认为Нет能让 Route Переписка element После нормального рендеринга вы можете существовать loader середина throw аномальный. В это время будет отображен «errorElement».

Язык кода:jsx
копировать
function loader({ request, params }) {
  const res = await fetch(`/api/properties/${params.id}`);
  if (res.status === 404) {
    throw new Response("Not Found", { status: 404 });
  }
  return res.json();
}
//...
<Route loader={loader} />

Уведомление:ты можешьбросить любойаномальный,все будет в порядкесуществовать errorElement пройти внутри hook useRouteError Приходитьполучатьприезжатьаномальный。

но,React Router Официальный совет вам throw Response:

Язык кода:jsx
копировать
<Route
  path="/properties/:id"
  element={<PropertyForSale />}
  errorElement={<PropertyError />}
  loader={async ({ params }) => {
    const res = await fetch(`/api/properties/${params.id}`);
    if (res.status === 404) {
      throw new Response("Not Found", { status: 404 });
    }
    const home = res.json();
    return { home };
  }}
/>

ты все еще можешь использовать его React Router Предоставить из json Метод, удобная конструкция индивидуальная Response:

Язык кода:txt
копировать
throw json(
  { message: "email is required" },
  { status: 400 },
);

2.3 <Route> element свойство

этотиндивидуальный Нетдановыйсвойство,Прямо сейчас<RouteПосле сопоставления,Рендеринг контента. Я хочу, чтобы это было из изменений:

2.3.1 доступен внутри useLoaderData получать loader возвращаемое значение

Обратите внимание, что если loader возвращаемое значениеда Ответ и Response из Content Type да application/json,React Router Он будет автоматически вызван внутри .json() метод, разработчику не нужно писать .json() .

Язык кода:jsx
копировать
function Albums() {
  const albums = useLoaderData();
  return <div>{albums}</div>;
}

const router = createBrowserRouter([
  {
    path: "/",
    loader: fetch("/api"),
    element: <Albums />,
  },
]);

ReactDOM.createRoot(el).render(
  <RouterProvider router={router} />
);

2.3.2 Внутренне вызываемый useRouteLoaderData получать другой Route из loader возвращаемое значение

Компоненты React могут быть вложенными,<Route>Также может быть вложенным,этотчас Можетпроходить该 hook получатьдругой <Route> из loader извозвращаемое значение. когда Однако вам необходимо предоставить id。

При определении маршрута:

Язык кода:javascript
копировать
createBrowserRouter([
  {
    path: "/",
    loader: () => fetchUser(),
    element: <Root />,
    id: "root",
    children: [
      {
        path: "jobs/:jobId",
        loader: loadJob,
        element: <JobListing />,
      },
    ],
  },
]);

<JobListing />Внутри部调использоватьэтотиндивидуальныйhookчас:

Язык кода:javascript
копировать
const user = useRouteLoaderData("root");

2.4 <Route> errorElement свойство

когда loader брошенный внутрьаномальный,<Route>Сразу Нет渲染этоиз element , в то время как да отображает его из errorElement。

2.4.1 Исключения могут всплывать

<Route> да может быть вложенным, и каждый уровень может быть определен errorElement, возникает аномальный элемент, будет найден ближайший из errorElement и отобразите его, а затем перестаньте всплывать.

2.4.2 доступен внутри useRouteError получатьаномальный

существовать errorElement внутри, доступен useRouteError получатьаномальный。

Язык кода:javascript
копировать
const error = useRouteError();

2.4.3 доступен внутри isRouteErrorResponse Определить тип исключения

React Router 给Понятноодининдивидуальныйфункция isRouteErrorResponse,帮тысуществоватьразвивать errorElement Когда когда раньше аномальныйда ли да Response аномальный. потому что Response аномальный в целомдаразвивать者自己抛出из,да может отображать причину (включая код ошибки, возвращаемый внутренним интерфейсом, и копию подсказки об ошибке),Также возможносуществоватьэтотвнутри处理)。другойаномальный,Обычно неизвестно из,Просто отобразите копию отчета об ошибках напрямую.

Язык кода:javascript
копировать
function RootBoundary() {
  const error = useRouteError();

  if (isRouteErrorResponse(error)) {
    if (error.status === 404) {
      return <div>This page doesn't exist!</div>;
    }
    if (error.status === 503) {
      return <div>Looks like our API is down</div>;
    }
  }

  return <div>Something went wrong</div>;
}

2.5 <Route> action свойство

Видите ли, это очень похоже на лаодер:

  • Также есть 2индивидуальных параметра: params и запрос. Определение loader Такой же.
  • Вы можете вернуть что угодно, и React Router рекомендует возвращать Response.
  • Вы также можете вернуть перенаправление, чтобы реализовать перенаправление.
  • существоватьelementВнутри,ты можешьиспользоватьhook useActionData получать action возвращаемое значение. (похожий useLoaderData

Разница в том, что они выполняются в разное время:

  • loader даузер прошел GET 导航至某路由час,Исполнение из.
  • action да Пользовательское представление form когда, сделай POST PUT DELETE При управлении ожиданием выполните из.

Написал раньше<form>из Все знают,Имеет параметр действия и метода.,существоватьдо,Отправка формы также меняет URL-адрес в браузере. использовать сообщение React,почти никто этого не делает,Все отправляют формы через AJAX или Fetch.

сейчассуществовать,React Router предоставил <Form> компоненты,и дать <Route> добавлены компоненты action свойство, позволяющее отправке формы стать одноразовым маршрутом.

Действительно, я больше не могу с этим поделать и хочу опубликовать его. мнение:Это кажется бесполезным, это бесполезно

если хочешь знать Route из action свойство, надо посмотреть React Router Form,Уведомление Form внутри也有индивидуальный action собственность, не путайтесь.

3. Другие функции React Router 6.4

когда Ран,React Router 6.4 Не только Data API У этого человека есть еще одно крупное обновление: Отложено. Data: Deferred Data Guide

Не могу не написать еще раз лично мнение: Зачем добавлять эту индивидуальную функцию? да Чтобы дать Data API «Вытри задницу».

Из-за введения загрузчика возникают внутренние запросы API, что неизбежно приводит к тому, что страница загружается долго при переключении маршрутизации. Что делать, если загрузка длится долго? Необходимо показать состояние загрузки.

  • Решение первое: не существовать loader Внутренние волосы API просить,существовать Route Переписка element Лифа запросить и показать Loading состояние. Реагировать Router предоставилинтимныйиз useFetcher,МожетсуществоватьelementВнутренние волосыпросить。
  • Решение 2. Для загрузчиков предоставьте решение по настройке, которое позволит разработчикам определять состояние загрузки.

React Router Доступны оба варианта. Первый вариант — да. useFetcher。为Понятно实сейчас方案二,это引入Понятноdeferфункцияи<Await>компоненты。

3.1 функция отсрочки

существовать loader Внутрииспользовать,表明этотиндивидуальный loader Нужно показать Loading состояние. если loader вернулся отложить, тогда он будет отображен напрямую <Route> из element。

Язык кода:jsx
копировать
<Route
  loader={async () => {
    let book = await getBook(); // Этот человек не будет отображаться Loading государство, потому что это await Да, оно будет выполнено и данные будут получены.
    let reviews = getReviews(); // этотиндивидуальныйвстречавыставка Loading состояние
    return defer({
      book, // Эти данные
      reviews, // Да promise
    });
  }}
  element={<Book />}
/>;

3.2 <Await> компоненты

существовать <Route> из element серединаиспользовать,использовать于выставка Loading состояние.нужно объединить<Suspense>использовать,Loading состояниевыставкасуществовать<Suspense> из fallback середина。

Язык кода:jsx
копировать
function Book() {
  const {
    book,
    reviews, // this is the same promise
  } = useLoaderData();
  return (
    <div>
      <h1>{book.title}</h1>
      <p>{book.description}</p>
      <React.Suspense fallback={<ReviewsSkeleton />}>
        <Await
          // and is the promise we pass to Await
          resolve={reviews}
        >
          <Reviews />
        </Await>
        />
      </React.Suspense>
    </div>
  );
}

ждать loader После загрузки он будет отображаться Await из children внутрииз Внутри容.

3.2.1 <Await> компонентыиз children свойство

Это может быть дафункция, а может быть да React-компоненты.

Если дафункция, результатом Promise будет дапараметр:

Язык кода:jsx
копировать
<Await resolve={reviewsPromise}>
  {(resolvedReviews) => <Reviews items={resolvedReviews} />}
</Await>

Если дакомпоненты,Внутри部проходитьuseAsyncValue получать Promise из результатов.

Язык кода:jsx
копировать
<Await resolve={reviewsPromise}>
  <Reviews />
</Await>;

function Reviews() {
  const resolvedReviews = useAsyncValue();
  return <div>{/* ... */}</div>;
}

личное мнение

Повторю свою основную мысль: React Router 6.4 Это больше не просто маршрут, он объединяет логику данных.

  • Если огромный проект,Некоторые данные получить логическисуществовать Маршрутизатор,Некоторые данные получают логическое существование внутренних компонентов. Это не способствует поддержанию проекта.
  • React Router 6.4 为Понятно加индивидуальный Data API, добавлено много кода. v6.4 Пакет УМД production.min.js Размер (16,1 КБ) да v6.3 Пакет УМД production.min.js(6.75KB) Объем 2.4 Двойной!

Тестирование пакета

Публичные зависимости:

Язык кода:txt
копировать
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",

Не ссылаться на React Router

После упаковки следующего кода 141199 B.

Язык кода:jsx
копировать
import React from 'react';
import ReactDOM from 'react-dom/client';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);

root.render(
  <React.StrictMode>
    <div />
  </React.StrictMode>,
);

React Router v6.3

После упаковки следующего кода 150266 B.

Язык кода:jsx
копировать
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);

root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route index element={<div />} />
      </Routes>
    </BrowserRouter>
  </React.StrictMode>,
);

React Router v6.4 не использует API данных

Код тот же, что и выше, 159758 B.

React Router v6.4 с использованием API данных

После упаковки следующего кода 196040 B.

Язык кода:txt
копировать
import React from 'react';
import ReactDOM from 'react-dom/client';
import {
  createBrowserRouter,
  RouterProvider,
} from 'react-router-dom';
import './index.css';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
const router = createBrowserRouter([
  {
    index: true,
    element: <div />,
  },
]);
root.render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>,
);

контраст

упаковочный материал

Объем (Б)

Рост из Объема (Б)

Относительный темп роста 6,3

Доля React Router в общем коде

Нет React-маршрутизатора

141199

0

-

-

React Router 6.3

150266

9067

1x

6%

React Router 6.4 не использует API данных

159758

18559

2,05 раза

12%

React Router 6.4 с использованием API данных

196040

54841

6,05 раз

28%

в заключение

В конечном итоге я хотел бы использовать react-router-dom=~6.3.0,Прямо сейчас Нет更новыйприезжать 6.4, всегда используйте 6.3.x。

после всего,яиз«Коллекция настольных онлайн-игр»внутри,HTTP-запросов нет. Я просто хочу использовать чистые компоненты индивидуального маршрута. А 6.4 нацелен на 6.3 издругой мелких фич,Я вообще не могу его использовать.

напиши в конце

Я да Халл Цинь,Официальный аккаунтОфлайн-игры для вечеринокизавтор(добро пожаловатьсосредоточиться меня, заведи индивидуальных друзей). Перед пересылкой этой статьи необходимо разрешение автора HullQin. Я самостоятельно разработал «Коллекцию настольных онлайн-игр»,индивидуальная веб-страница,Друзьям очень удобно играть в ООН, Помещики, нарды, Летающие шахматы, Один Ночной Волк, шахматы, Немецкая Болезнь Сердца, Код Да Винчи ждать онлайн.,Нет收费никторекламировать。还развивать Понятно《Dice Crush》УчастиеGame Jam 2022。喜欢Можетсосредоточиться ная噢~я有空Понятновстреча分享做游戏из Связанный技术,встречасуществоватьэтотиндивидуальный专栏внутри分享:《Научите вас играть в маленькие игры》

boy illustration
13. Springboot интегрирует Protobuf
boy illustration
Примечание. Инструмент управления батареями Dell Dell Power Manager
boy illustration
Общая интерпретация класса LocalDate [java]
boy illustration
[Базовые знания ASP.NET Core] -- Веб-API -- Создание и настройка веб-API (1)
boy illustration
Настоящий бой! Подключите Passkey к своему веб-сайту для безопасного входа в систему без пароля.
boy illustration
Руководство по настройке Nginx: как найти, интерпретировать и оптимизировать настройки Nginx в Linux
boy illustration
Typecho отображает использование памяти сервера
boy illustration
Как вставить элемент перед указанным ключом в ассоциативный массив в PHP
boy illustration
swagger2 экспортирует API как текстовый документ (реализация Java) [легко понять]
boy illustration
Выбор фреймворка nodejs Express koa egg MidwayJS сравнение NestJS
boy illustration
Руководство по загрузке, установке и использованию SVN «Рекомендуемая коллекция»
boy illustration
Интерфейс PHPforwarding_php отправляет запрос на получение
boy illustration
Создавайте и защищайте связь в реальном времени с помощью SignalR и Azure Active Directory.
boy illustration
ВичатПубличная платформаразвивать(три)——ВичатQR-кодгенерировать&Сканировать кодсосредоточиться на
boy illustration
[Углубленное понимание Java IO] Используйте InputStreamReader для чтения содержимого файла и легкого выполнения задач преобразования текста.
boy illustration
сравнение строк PHP
boy illustration
9 сценариев асинхронного сбоя @Async
boy illustration
Эффективная обработка запланированных задач: углубленное изучение секретов библиотеки APScheduler на Python
boy illustration
Рекомендации по облегченному артефакту развязки внутренних компонентов Spring Event (событие Spring)
boy illustration
Go: Лесоруб-лесоруб на колесах Введение
boy illustration
Основы серверной разработки: технология кэширования, которую должен освоить каждый программист
boy illustration
Java Advanced Collections TreeSet: что это такое и зачем его использовать?
boy illustration
Оказывается, у команды go build столько знаний
boy illustration
Node.js
boy illustration
Анализ исходного кода, связанный с запланированными задачами версии ruoyi-vue (7), то есть анализ модуля ruoyi-quartz.
boy illustration
Вход в систему с помощью скан-кода WeChat (1) — объяснение процесса входа в систему со скан-кодом, получение авторизованного QR-кода для входа.
boy illustration
HikariPool-1 — обнаружено отсутствие потока или скачок тактовой частоты, а также конфигурация источника данных Hikari.
boy illustration
Сравнение высокопроизводительной библиотеки JSON Go
boy illustration
Простое руководство по извлечению аудио с помощью FFmpeg
boy illustration
Подсчитайте количество строк кода в проекте