Что, React Router вышел на V6? ?

внешний интерфейс React.js
Что, React Router вышел на V6? ?

По внезапной прихоти на прошлой неделеreact-routerгитхаб посмотрел, молодец, пришла последняя версия6.0.0-beta.8(Выпущено 2021.11.46.0.0Официальная версия), и все переписано с ts (представляющим похвалу!!), конкретные изменения можно увидетьMigrating React Router v5 to v6. Я не знаю, не вижу ли я этого, но я был поражен, когда увидел это, и обнаружил, что изменения были довольно большими.apiОн также стал проще в использовании, чем раньше. Затем я постараюсь предоставить различные примеры, чтобы представить некоторые часто используемыеapiизменения, чтобы все были более знакомы с последним использованием.

все изменено на

а такжеSwitchв сравнении с,RoutesОсновные преимущества:

  • Routesвсе внутри<Route>а также<Link>является относительным. Это делает<Route path>а также<Link to>Более компактный и предсказуемый код в
  • Маршруты выбираются на основе наилучшего совпадения, а не по порядку
  • Маршруты могут быть вложены в одном месте, а не разбросаны по разным компонентам (конечно, их можно прописать и в подкомпонентах), а вложенные родительские маршрутыpathнет необходимости добавлять*
import {
  BrowserRouter,
  Routes,
  Route,
  Link,
  Outlet
} from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        {* 上面的优点一:path是相对的 *}
        {* 上面的优点三:path 不用加'*' *}
        <Route path="users" element={<Users />}>
          {* 上面的优点二: 无需按顺序 *}
          {* 上面的优点三: 路由可以嵌套在一个地方 *}
          <Route path="me" element={<OwnUserProfile />} />
          <Route path=":id" element={<UserProfile />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

function Users() {
  return (
    <div>
      <nav>
        {* 上面的优点一: <Link to>是相对的 *}
        <Link to="me">My Profile</Link>
      </nav>
      {* Outlet后面会讲 *}
      <Outlet />
    </div>
  );
}

Обратите внимание на третий пункт выше,К пути вложенного родительского маршрута не нужно добавлять *. Но если он не вложен, а разбросан по подкомпонентам, его нужно добавить в конце*


function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        {* 不是嵌套就需要尾部加上* *}
        <Route path="users/*" element={<Users />} />
      </Routes>
    </BrowserRouter>
  );
}
function Users() {
  return (
    <Routes>
      <Route element={<UsserLayout />}>
        <Route path="me" element={<OwnUserProfile />} />
        <Route path=":id" element={<UserProfile />} />
      </Route>
    </div>
  );
}
function UsersLayout() {
  return (
    <div>
      <nav>
        <Link to="me">My Profile</Link>
        <Link to="2">User Profile</Link>
      </nav>
      <Outlet />
    </div>
  );
}

<Route>

<Route element>

Рендеринг или компонент маршрута изменены наelement

   <Route path=":userId" element={<Profile animate={true} /> />

   function Profile({ animate }) {
     const params = useParams();
     const location = useLocation();
   }

Через эту форму:

  • Вы можете передавать реквизиты компонентам, как указано выше.animate={true}
  • Из-за появления хуков больше не нужно передавать некоторые реквизиты маршрута к компоненту через renderProps, мы можем передатьuseParams,useLocationполучить эту информацию

Конечно, есть еще одна важная причина, потому чтоv6Дети маршрута используются для вложенных маршрутов, как показано ниже.

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="users" element={<Users />}>
          <Route path="me" element={<OwnUserProfile />} />
          <Route path=":id" element={<UserProfile />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

тогда мы собираемся показатьOwnUserProfile компоненты проходят/users/meЕго можно найти, что кажется довольно интуитивным

<Route path>

v6имитироватьpathформате поддерживаются только два динамических заполнителя:

  • :idпараметр стиля
  • *Подстановочные знаки, которые можно использовать только в конце пути, напримерusers/*

дать 🌰

Верны следующие пути:

path = '/groups'
path = '/groups/admin'
path = '/users/:id'
path = '/users/:id/messages'
path = '/files/*' // 通配符放在末尾
path = '/files/:id/*'
path = '/files-*'

Следующий путь неверный:

path = '/users/:id?' // ? 不满足上面两种格式
path = '/tweets/:id(\d+)' // 有正则,不满足上面两种格式
path = '/files/*/cat.jpg'// 通配符不能放中间

<Route caseSensitive>

caseSensitive: boolean, включать ли режим игнорирования при сопоставлении пути, то есть игнорировать ли регистр при сопоставлении

часть исходного кода

// 根据path生成是regexpSource是否要ignore
const matcher = new RegExp(regexpSource, caseSensitive ? undefined : "i");

<Route index>

indexОзначает, является ли маршрут основным. Если установлено значение true, у него не может быть дочерних элементов, как показано ниже.<Route index element={<Home />} />

function App() {
  return (
    <Routes>
      <Route path='/' element={<Layout />}>
        <Route path='auth/*' element={<Auth/> } />
        <Route path='basic/*' element={<Basic/> } />
      </Route>
    </Routes>
  )
}
function Home() {
  return (
    <h2> Home </h2>
  )
}
function Basic() {
  return (
    <div>
      <h1>Welcome to the app!</h1>
      <h2>下面()中的就是真实的Link组件</h2>
      <Routes>
        <Route element={<Layout />}>
          <Route index element={<Home />} />
          <Route path="about" element={<About />}/>
          ...
        </Route>
      </Routes>
    </div>
  );
}

Так/basicавтоматически покажет<Home />

и

Макет используется во многих приведенных выше примерах, какая от этого польза? а такжеOutletЧто это значит?

Давайте посмотрим на код (он лучше работает с картинкой ниже)

function App() {
  return (
    <Routes>
      <Route path='/' element={<Layout />}>
        <Route path='auth/*' element={<Auth/> } />
        <Route path='basic/*' element={<Basic/> } />
      </Route>
    </Routes>
  )
}

// 下图的最外面的红色框
function Layout() {
  return (
    <>
     <p>主页面</p>
      <ul>
        <li>
          <Link to='auth'>auth</Link>
        </li>
         <li>
          <Link to='basic'>basic</Link>
        </li>
      </ul>
      <hr />
      {* 下图蓝色框 *}
      <Outlet />
    </>
  )
}

function Basic() {
  return (
    <div>
      <h1>Welcome to the app!</h1>
      <h2>下面()中的就是真实的Link组件</h2>
      <Routes>
        <Route element={<BasicLayout />}>
          <Route index element={<Home />} />
          <Route path="about" element={<About />}/>
          ...
        </Route>
      </Routes>
    </div>
  );
}
// 下图绿色框
function BasicLayout() {
  return (
    <div>
      <ul>
          ...
          <Link to=".">Home({` <Link to=".">`})</Link>
          ...
        </li>
      </ul>
    <Outlet />
    </div>
  );
}
// 下图黄色框
function Home() {
  return (
    <h2>Home</h2>
  )
}

Из кода и схемы выше мы можем знать, что компонент<Layout/>Обычно используется как элемент родительского маршрута, в дополнение к рендерингу общедоступного пользовательского интерфейса также есть элементы для рендеринга подмаршрутов.<Outlet/>, а в коде<Outlet/>отображается<Basic/>,<Basic>из<BasicLayout />Существуют<Outlet/>, но он отображает<Route element={<BasicLayout />}>Элемент, соответствующий маршруту.

Из вышеизложенного мы можем сделать вывод, что:компоненты<Layout/>Обычно используется как элемент родительского маршрута, в дополнение к рендерингу некоторых общедоступных интерфейсов, среди них<Outlet/>Функция аналогична слоту, который используется для сопоставления элемента подмаршрута.

useRoutes

Выше мы все используем Route как потомков Routes

function App() {
  return (
    <Routes>
      <Route path='/' element={<Layout />}>
        <Route path='auth/*' element={<Auth/> } />
        <Route path='basic/*' element={<Basic/> } />
      </Route>
    </Routes>
  )
}

Но мы также можемuseRoutesСоздайте соответствующий элемент

import  { useRoutes } from 'react-router-dom'
function App() {
  const element = useRoutes([
    {
      path: '/',
      element: <Layout />,
      children: [
        {
          path: 'auth/*',
          element: <Auth/>
        },
        {
          path: 'basic/*',
          element: <Basic/>
        }
      ]
    }
  ])
  return (
     {element}
  )
}

Этот элемент конфигурации позволяет нам более четко увидеть вложенную структуру маршрута.

<Link>

<Link to>

существуетv5, еслиtoНе/Это немного запутано начать с тем, что это зависит от текущего URL. Например, текущий URL/user, Так<Link to="me">будет отображаться как<a href="/me">; и если это/users/, то он будет отображаться как<a href="/users/me">.

Затем вv6решает загадочное явление выше.

существуетv6, является ли текущий URL/userеще/users/,<Link to="me">будет отображаться как<a href='/user/me'>.

то естьtoбольше похоже на наше обычноеcdКомандная строка, давайте посмотрим больше примеров


<Route path="app">
  <Route path="dashboard">
    <Route path="stats" />
  </Route>
</Route>

//  当前 URL 为 /app/dashboard 或 /app/dashboard/
<Link to="stats">               => <a href="/app/dashboard/stats">
<Link to="../stats">            => <a href="/app/stats">
<Link to="../../stats">         => <a href="/stats">
<Link to="../../../stats">      => <a href="/stats">

// 命令行中, 当前目录为 /app/dashboard
cd stats                        # pwd is /app/dashboard/stats
cd ../stats                     # pwd is /app/stats
cd ../../stats                  # pwd is /stats
cd ../../../stats               # pwd is /stats

Важно отметить, что когда<Route path>При сопоставлении нескольких фрагментов URL<Link to="..">не всегда отображается как<a href="..">, в этом случаеto='..'это путь, основанный на родительском маршруте, пример выглядит следующим образом

function App() {
  return (
    <Routes>
      <Route path="users">
        <Route
          path=":id/messages"
          element={
            // 最终是/users, 而不是/:id
            <Link to=".." />
          }
        />
      </Route>
    </Routes>
  );
}

Если вы этого еще не поняли, мы можем привести крайний пример, например, путь маршрутаbasic/*, текущий URL-адрес/basic/auth/home, следующий код

function App() {
  return (
    <Routes>
      <Route path="/">
        <Route path="auth/*" element={<Auth />} />
        <Route
          path="basic/*"
          element={
            ...
            <Link to="../auth" />
            ...
          }
        />
      </Route>
    </Routes>
  );

тогда вышеto="../auth"это прыгнуть к/basic/authеще/auth(ответ/auth)? Так что во избежание*Подстановочные знаки могут соответствовать нескольким путям, унифицированным какto='..'это путь, основанный на родительском маршруте

<Link state>

То есть после нажатия можно датьtoпройти соответствующийstate

<Link replace>

replace:boolean, по умолчанию false, то есть используется маршрут переходаpushещеreplace

<Link target>

тип цели

type HTMLAttributeAnchorTarget =
        | '_self'
        | '_blank'
        | '_parent'
        | '_top'
        | (string & {});

На самом деле мы этим почти не пользуемся, здесь мы лишь кратко представим значения, которые можно передавать.

useHistory удален и заменен на useNavigate.

Способ применения следующий:

// v6
import { useNavigate } from "react-router-dom";

function App() {
  const navigate = useNavigate();
  function handleClick() {
    navigate("/home");
  }
  return (
    <div>
      <button onClick={handleClick}>go home</button>
    </div>
  );
}

перейти(к) по умолчанию на history.push

// v6
navigate('/home');
//v5
history.push('/home')

перейти (к, { заменить: правда }) is history.replace

// v6
navigate('/home', { replace: true });
//v5
history.replace('/home')

перейти (к: номеру) is history.go

// v6
import { useNavigate } from "react-router-dom";

function App() {
  const navigate = useNavigate();

  return (
    <>
      <button onClick={() => navigate(-2)}>
        Go 2 pages back
      </button>
      <button onClick={() => navigate(-1)}>Go back</button>
      <button onClick={() => navigate(1)}>
        Go forward
      </button>
      <button onClick={() => navigate(2)}>
        Go 2 pages forward
      </button>
    </>
  );
}
//  v5
import { useHistory } from "react-router-dom";

function App() {
  const { go, goBack, goForward } = useHistory();

  return (
    <>
      <button onClick={() => go(-2)}>
        Go 2 pages back
      </button>
      <button onClick={goBack}>Go back</button>
      <button onClick={goForward}>Go forward</button>
      <button onClick={() => go(2)}>
        Go 2 pages forward
      </button>
    </>
  );
}

naviagete такой же, как , входные параметры аналогичны командной строке cd


<Route path="app">
  <Route path="dashboard">
    <Route path="stats" />
  </Route>
</Route>

//  当前 URL 为 /app/dashboard 或 /app/dashboard/
<Link to="stats">               => <a href="/app/dashboard/stats">
<Link to="../stats">            => <a href="/app/stats">
<Link to="../../stats">         => <a href="/stats">
<Link to="../../../stats">      => <a href="/stats">

//  当前 URL 为 /app/dashboard 或 /app/dashboard/
const navigate = useNavigate()
navigate('stats') => '/app/dashboard/stats'
navigate('../stats') => '/app/stats'
navigate('../../stats') => '/stats'
navigate('../../../stats') => '/stats'

// 命令行中, 当前目录为 /app/dashboard
cd stats                        # pwd is /app/dashboard/stats
cd ../stats                     # pwd is /app/stats
cd ../../stats                  # pwd is /stats
cd ../../../stats               # pwd is /stats

Эпилог

Ну, это почти здесь, давайте подытожим некоторые изменения:

  • <Switch>изменить все на<Routes>
  • Routeизrenderа такжеcomponentизменить наelement, и может вкладывать маршруты
  • RouteВы также можете сгенерировать соответствующий элемент, передав вложенный массив в useRoutes.
  • to,navigate,pathНе/являются относительными путями в начале, сcdкомандная строка как
  • <Outlet />это слот, который может отображать совпадающие подмаршруты

Если вы хотите узнать больше примеров, вы можете открытьreact-router-source-analysis, с большим количеством примеров.

Пока это должно быть, наверное, может анализ исходного кода последнего React-Router в Китае.Если интересно, можете глянуть.Если считаете, что можете, не поскупитесь на свой ⭐

наконец

надо написать позжеReact-RouterПоследняя статья по анализу исходного кода, если не ошибаюсь 🐶🐶, ха-ха.

end-cover.png

Спасибо, что оставили свои следы.Если вы считаете, что статья хорошая😄😄, пошевелите пожалуйста пальчиками😋😋, лайк + в избранное + вперед🌹🌹

Прошлые статьи

Перевод перевод, что такое ReactDOM.createRoot

Перевод перевод, что такое JSX