迁移react路由器 React Router v5 到 v6

starkwang

# Migrating React Router v5 to v6

*Note: This document is still a work in progress! The migration process from
React Router v5 to v6 isn't yet as smooth as we would like it to be. We are
planning on backporting several of v6's new APIs to v5 to make it smoother, and
this guide will keep improving as we continue to gather feedback.*

React Router version 6 introduces several powerful new features, as well as
improved compatibility with the latest versions of React. It also introduces a
few breaking changes from version 5. This document is a comprehensive guide on
how to upgrade your v4/5 app to v6 while hopefully being able to ship as often
as possible as you go.

If you are just getting started with React Router or you'd like to try out v6 in
a new app, please see [the Getting Started guide](../installation/getting-started.md).

The examples in this guide will show code samples of how you might have built
something in a v5 app, followed by how you would accomplish the same thing in
v6. There will also be an explanation of why we made this change and how it's
going to improve both your code and the overall user experience of people who
are using your app.

In general, the process looks like this:

  • [Upgrade to React v16.8 or greater](#upgrade-to-react-v168)
  • [Upgrade to React Router v5.1](#upgrade-to-react-router-v51)

    • Use `<Route children>` everywhere
    • Use hooks instead of `withRouter` and "floating" `<Route>`s (that aren't
      part of a `<Switch>`)
  • [Upgrade to React Router v6](#upgrade-to-react-router-v6)

    • [Upgrade all `<Switch>` elements to `<Routes>`](#upgrade-all-switch-elements-to-routes)

      • Update `<Link to>` values
      • Update `<Route path>` patterns
      • Remove `<Route exact>` and `<Route strict>` props
      • Move `<Route sensitive>` to containing `<Routes caseSensitive>`
      • Consolidate your `<Route>`s into a nested config (optional)
    • [Use `navigate` instead of `history`](#use-navigate-instead-of-history)

      • Use `useNavigate` hook instead of `useHistory`
      • Use `<Navigate>` instead of `<Redirect>` (outside of route configs)

        • No need to change `<Redirect>` directly inside `<Routes>`
    • [Use `useRoutes` instead of `react-router-config`](#use-useroutes-instead-of-react-router-config)
    • [Rename `<Link component>` to `<Link as>`](#rename-link-component-to-link-as)
    • [Get `StaticRouter` from `react-router-dom/server`](#get-staticrouter-from-react-router-domserver)

Upgrade to React v16.8

React Router v6 makes heavy use of [React
hooks](https://reactjs.org/docs/hook... so you'll need to be on React
16.8 or greater before attempting the upgrade to React Router v6. The good news
is that React Router v5 is compatible with React >= 15, so if you're on v5 (or
v4) you should be able to upgrade React without touching any of your router
code.

Once you've upgraded to React 16.8, **you should deploy your app**. Then you can
come back later and pick up where you left off.

Upgrade to React Router v5.1

It will be easier to make the switch to React Router v6 if you upgrade to v5.1
first. In v5.1, we released an enhancement to the handling of `<Route children>`
elements that will help smooth the transition to v6. Instead of using `<Route
component>` and `<Route render>` props, just use regular element `<Route
children>` everywhere and use hooks to access the router's internal state.

```js
// v4 and v5 before 5.1
function User({ id }) {
// ...
}

<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route

path="/users/:id"
render={
  ({ match }) => <User id={match.params.id} />
}

/>
</Switch>

// v5.1 preferred style
function User() {
let { id } = useParams();
// ...
}

<Switch>
<Route exact path="/"><Home /></Route>
<Route path="/about"><About /></Route>
{/* Can also use a named `children` prop */}
<Route path="/users/:id" children={<User />} />
</Switch>
```

You can read more about v5.1's hooks API and the rationale behind the move to
regular elements [on our blog](https://reacttraining.com/blo...

In general, React Router v5.1 (and v6) favors elements over components (or
"element types"). There are a few reasons for this, but we'll discuss more
further down when we discuss v6's `<Route>` API.

When you use regular React elements you get to pass the props
explicitly. This helps with code readability and maintenance over time. If you
were using `<Route render>` to get a hold of the params, you can just
`useParams` inside your route component instead.

Along with the upgrade to v5.1, you should replace any usage of `withRouter`
with hooks. You should also get rid of any "floating" `<Route>` elements that
are not inside a `<Switch>`. Again, [the blog post about
v5.1](https://reacttraining.com/blo... explains how to do this
in greater detail.

In summary, to upgrade from v4/5 to v5.1, you should:

  • Use `<Route children>` instead of `<Route render>` and/or `<Route component>`
    props
  • Use [our hooks API](https://reacttraining.com/rea... to
    access router state like the current location and params
  • Replace all uses of `withRouter` with hooks
  • Replace any `<Route>`s that are not inside a `<Switch>` with `useRouteMatch`,
    or wrap them in a `<Switch>`

Again, **once your app is upgraded to v5.1 you should test and deploy it**, and
pick this guide back up when you're ready to continue.

Upgrade to React Router v6

**Heads up:** This is the biggest step in the migration and will probably take
the most time and effort.

For this step, you'll need to install React Router v6. If you're managing
dependencies via npm:

```
$ npm install react-router@6 react-router-dom@6

or, for a React Native app

$ npm install react-router@6 react-router-native@6
```

Upgrade all `<Switch>` elements to `<Routes>`

React Router v6 introduces a `Routes` component that is kind of like `Switch`,
but a lot more powerful. The main advantages of `Routes` over `Switch` are:

  • All `<Route>`s and `<Link>`s inside a `<Routes>` are relative. This leads to
    leaner and more predictable code in `<Route path>` and `<Link to>`
  • Routes are chosen based on the best match instead of being traversed in order.
    This avoids bugs due to unreachable routes because they were defined later
    in your `<Switch>`
  • Routes may be nested in one place instead of being spread out in different
    components. In small to medium sized apps, this lets you easily see all your
    routes at once. In large apps, you can still nest routes in bundles that you
    load dynamically via `React.lazy`

In order to use v6, you'll need to convert all your `<Switch>` elements to
`<Routes>`. If you already made the upgrade to v5.1, you're halfway there.

First, let's talk about relative routes and links in v6.

Relative Routes and Links

In v5, you had to be very explicit about how you wanted to nest your routes and
links. In both cases, if you wanted nested routes and links you had to build the
`<Route path>` and `<Link to>` props from the parent route's `match.url` and
`match.path` properties. Additionally, if you wanted to nest routes, you had to
put them in the child route's component.

```js
// This is a React Router v5 app
import { BrowserRouter, Switch, Route, Link, useRouteMatch } from 'react-router-dom';

function App() {
return (

<BrowserRouter>
  <Switch>
    <Route exact path="/"><Home /></Route>
    <Route path="/users"><Users /></Route>
  </Switch>
</BrowserRouter>

);
}

function Users() {
// In v5, nested routes are rendered by the child component, so
// you have <Switch> elements all over your app for nested UI.
// You build nested routes and links using match.url and match.path.
let match = useRouteMatch();

return (

<div>
  <nav>
    <Link to={\`${match.url}/me\`}>My Profile</Link>
  </nav>

  <Switch>
    <Route path={\`${match.path}/me\`}><OwnUserProfile /></Route>
    <Route path={\`${match.path}/:id\`}><UserProfile /></Route>
  </Switch>
</div>

);
}
```

This is the same app in v6:

```js
// This is a React Router v6 app
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

function App() {
return (

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="users/\*" element={<Users />} />
  </Routes>
</BrowserRouter>

);
}

function Users() {
return (

<div>
  <nav>
    <Link to="me">My Profile</Link>
  </nav>

  <Routes>
    <Route path=":id" element={<UserProfile />} />
    <Route path="me" element={<OwnUserProfile />} />
  </Routes>
</div>

);
}
```

A few important things to notice about v6 in this example:

  • `<Route path>` and `<Link to>` are relative. This means that they
    automatically build on the parent route's path and URL so you don't have to
    manually interpolate `match.url` or `match.path`
  • `<Route exact>` is gone. Instead, routes with descendant routes (defined in
    other components) use a trailing `*` in their path to indicate they match
    deeply
  • You may put your routes in whatever order you wish and the router will
    automatically detect the best route for the current URL. This prevents bugs
    due to manually putting routes in the wrong order in a `<Switch>`

You may have also noticed that all `<Route children>` from the v5 app changed to
`<Route element>` in v6. Assuming you followed the upgrade steps to v5.1, this
should be as simple as moving your route element from the child position to a
named `element` prop (TODO: can we provide a codemod here?).

Advantages of `<Route element>`

In the section about upgrading to v5.1, I promised you we'd discuss the
advantages of using regular elements instead of components (or element types)
for rendering. Let's take a quick break from upgrading and talk about that now.

For starters, we see React itself taking the lead here with the `<Suspense
fallback={<Spinner />}>` API. The `fallback` prop takes a React element, not a
component. This lets you easily pass whatever props you want to your `<Spinner>`
from the component that renders it.

Using elements instead of components means we don't have to provide a
`passProps`-style API so you can get the props you need to your elements. For
example, in a component-based API there is no good way to pass props to the
`<Profile>` element that is rendered when `<Route path=":userId"
component={Profile} />` matches. Most React libraries who take this approach end
up with either an API like `<Route component={Profile} passProps={{ animate:
true }} />` or use a render prop or higher-order component.

Also, I'm not sure if you noticed this but in v4 and v5, `Route`'s rendering API
became rather large. It went something like this:

```js
// Ah, this is nice and simple!
<Route path=":userId" component={Profile} />

// But wait, how do I pass custom props to the <Profile> element??
// Hmm, maybe we can use a render prop in those situations?
<Route
path=":userId"
render={routeProps => (

<Profile routeProps={routeProps} animate={true} />

)}
/>

// Ok, now we have two ways to render something with a route. :/

// But wait, what if we want to render something when a route
// *doesn't* match the URL, like a Not Found page? Maybe we
// can use another render prop with slightly different semantics?
<Route
path=":userId"
children={({ match }) => (

match ? (
  <Profile match={match} animate={true} />
) : (
  <NotFound />
)

)}
/>

// What if I want to get access to the route match, or I need
// to redirect deeper in the tree?
function DeepComponent(routeStuff) {
// got routeStuff, phew!
}
export default withRouter(DeepComponent);

// Well hey, now at least we've covered all our use cases!
// ... *facepalm*
```

At least part of the reason for this API sprawl was that React did not provide
any way for us to get the information from the `<Route>` to your route element,
so we had to invent clever ways to get both the route data **and** your own
custom props through to your elements: `component`, render props, `passProps`
higher-order-components ... until **hooks** came along!

Now, the conversation above goes like this:

```js
// Ah, nice and simple API. And it's just like the <Suspense> API!
// Nothing more to learn here.
<Route path=":userId" element={<Profile />} />

// But wait, how do I pass custom props to the <Profile>
// element? Oh ya, it's just an element. Easy.
<Route path=":userId" element={<Profile animate={true} />} />

// Ok, but how do I access the router's data, like the URL params
// or the current location?
function Profile({ animate }) {
let params = useParams();
let location = useLocation();
}

// But what about components deep in the tree?
function DeepComponent() {
// oh right, same as anywhere else
let navigate = useNavigate();
}

// Aaaaaaaaand we're done here.
```

Another important reason for using the `element` prop in v6 is that `<Route
children>` is reserved for nesting routes. This is one of people's favorite
features from v3 and @reach/router, and we're bringing it back in v6. Taking
the code in the previous example one step further, we can hoist all `<Route>`
elements into a single route config:

```js
// This is a React Router v6 app
import { BrowserRouter, Routes, Route, Link, Outlet } from 'react-router-dom';

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>

);
}

function Users() {
return (

<div>
  <nav>
    <Link to="me">My Profile</Link>
  </nav>

  <Outlet />
</div>

)
}
```

This step is optional of course, but it's really nice for small to medium sized
apps that don't have thousands of routes.

Notice how `<Route>` elements nest naturally inside a `<Routes>` element. Nested
routes build their path by adding to the parent route's path. We didn't need a
trailing `*` on `<Route path="users">` this time because when the routes are
defined in one spot the router is able to see all your nested routes.

You'll only need the trailing `*` when there is another `<Routes>` somewhere in
that route's descendant tree. In that case, the descendant `<Routes>` will match
on the portion of the pathname that remains (see the previous example for what
this looks like in practice).

When using a nested config, routes with `children` should render an `<Outlet>`
in order to render their child routes. This makes it easy to render layouts with
nested UI.

Note on `<Route path>` patterns

React Router v6 uses a simplified path format. `<Route path>` in v6 supports
only 2 kinds of placeholders: dynamic `:id`-style params and `*` wildcards. A
`*` wildcard may be used only at the end of a path, not in the middle.

All of the following are valid route paths in v6:

```
/groups
/groups/admin
/users/:id
/users/:id/messages
/files/*
/files/:id/*
/files-*
```

The following RegExp-style route paths are **not valid** in v6:

```
/users/:id?
/tweets/:id(\d+)
/files/*/cat.jpg
```

We added the dependency on path-to-regexp in v4 to enable more advanced pattern
matching. In v6 we are using a simpler syntax that allows us to predictably
parse the path for ranking purposes. It also means we can stop depending on
path-to-regexp, which is nice for bundle size.

If you were using any of path-to-regexp's more advanced syntax, you'll have to
remove it and simplify your route paths. If you were using the RegExp syntax to
do URL param validation (e.g. to ensure an id is all numeric characters) please
know that we plan to add some more advanced param validation in v6 at some
point. For now, you'll need to move that logic to the component the route
renders, and let it branch it's rendered tree after you parse the params.

If you were using `<Route sensitive>` you should move it to its containing
`<Routes caseSensitive>` prop. Either all routes in a `<Routes>` element are
case-sensitive or they are not.

One other thing to notice is that all path matching in v6 ignores the trailing
slash on the URL. In fact, `<Route strict>` has been removed and has no effect
in v6. **This does not mean that you can't use trailing slashes if you need
to.** Your app can decide to use trailing slashes or not, you just can't
render two different UIs *client-side* at `<Route path="edit">` and
`<Route path="edit/">`. You can still render two different UIs at those URLs,
but you'll have to do it server-side.

Note on `<Link to>` values

In v5, a `<Link to>` value that does not begin with `/` was ambiguous; it depends
on what the current URL is. For example, if the current URL is `/users`, a v5
`<Link to="me">` would render a ``. However, if the current URL
has a trailing slash, like `/users/`, the same `<Link to="me">` would render `<a
href="/users/me">`. This makes it difficult to predict how links will behave, so
in v5 we recommended that you build links from the root URL (using `match.url`)
and not use relative `<Link to>` values.

React Router v6 fixes this ambiguity. In v6, a `<Link to="me">` will always
render the same ``, regardless of the current URL.

For example, a `<Link to="me">` that is rendered inside a `<Route path="users">`
will always render a link to `/users/me`, regardless of whether or not the
current URL has a trailing slash. If you'd like to link to `/me` instead, you
can go up one segment of the URL using `..`, like `<Link to="../me">`. The `..`
basically means "remove one segment of the current URL", regardless of whether
it has a trailing slash or not. Of course, you can always `<Link to="/me">` if
you'd like to use an absolute URL instead.

It may help to think about the current URL as if it were a directory path on the
filesystem and `<Link to>` like the `cd` command line utility.

```
// If the current URL is /app/dashboard (with or without
// a trailing slash)
<Link to="stats"> //
<Link to="../stats"> //

<Link to="../../stats"> //

<Link to="../../../stats"> //

// On the command line, if the current directory is /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
```

**Note**: The decision to ignore trailing slashes while matching and creating relative
paths was not taken lightly by our team. We consulted with a number of
our friends and clients (who are also our friends!) about it. We found that
most of us don't even understand how plain HTML relative links are handled
with the trailing slash. Most people guessed it worked like `cd` on the
command line (it does not). Also, HTML relative links don't have the concept of nested
routes, they only worked on the URL, so we had to blaze our own trail here a bit.
@reach/router set this precendent and it has worked out well for a couple of
years.

Use useRoutes instead of react-router-config

All of the functionality from v5's `react-router-config` package has moved into
core in v6. If you prefer/need to define your routes as JavaScript objects
instead of using React elements, you're going to love this.

```js
function App() {
let element = useRoutes([

// These are the same as the props you provide to <Route>
{ path: '/', element: <Home /> },
{ path: 'dashboard', element: <Dashboard /> },
{ path: 'invoices',
  element: <Invoices />,
  // Nested routes use a children property, which is also
  // the same as <Route>
  children: \[
    { path: ':id', element: <Invoice /> },
    { path: 'sent', element: <SentInvoices /> }
  \]
},
// Redirects use a redirectTo property to
{ path: 'home', redirectTo: '/' },
// Not found routes work as you'd expect
{ path: '\*', element: <NotFound /> }

]);

// The returned element will render the entire element
// hierarchy with all the appropriate context it needs
return element;
}
```

Routes defined in this way follow all of the same semantics as `<Routes>`. In
fact, `<Routes>` is really just a wrapper around `useRoutes`. Crazy, I know.

We encourage you to give both `<Routes>` and `useRoutes` a shot and decide for
yourself which one you prefer to use. Honestly, we like and use them both.

If you had cooked up some of your own logic around data fetching and rendering
server-side, we have a low-level `matchRoutes` function available as well
similar to the one we had in react-router-config.

Use navigate instead of history

React Router v6 introduces a new navigation API that is synonymous with `<Link>`
and provides better compatibility with suspense-enabled apps. We include both
imperative and declarative versions of this API depending on your style and
needs.

```js
// This is a React Router v5 app
import { useHistory } from 'react-router-dom';

function App() {
let history = useHistory();
function handleClick() {

history.push('/home')

}
return (

<div>
  <button onClick={handleClick}>go home</button>
</div>

);
}
```

In v6, this app should be rewritten to use the `navigate` API. Most of the time
this means changing `useHistory` to `useNavigate` and changing the
`history.push` or `history.replace` callsite.

```js
// This is a React Router v6 app
import { useNavigate } from 'react-router-dom';

function App() {
let navigate = useNavigate();
function handleClick() {

navigate('/home')

}
return (

<div>
  <button onClick={handleClick}>go home</button>
</div>

);
}
```

If you need to replace the current location instead of push a new one onto the
history stack, use `navigate(to, { replace: true })`. If you need state, use
`navigate(to, { state })`. You can think of the first arg to `navigate` as your
`<Link to>` and the other arg as the `replace` and `state` props.

If you prefer to use a declarative API for navigation (ala v5's `Redirect`
component), v6 provides a `Navigate` component. Use it like:

```js
import { Navigate } from 'react-router-dom';

function App() {
return <Navigate to="/home" replace state={state} />;
}
```

If you're currently using `go`, `goBack` or `goForward` from `useHistory` to
navigate backwards and forwards, you should also replace these with `navigate`
with a numerical argument indicating where to move the pointer in the history
stack. For example, here is some code using v5's `useHistory` hook:

```js
// This is a React Router v5 app
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>
</>

);
}
```

Here is the equivalent app with v6:

```js
// This is a React Router v6 app
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>
</>

);
}
```

Again, one of the main reasons we are moving from using the `history` API
directly to the `navigate` API is to provide better compatibility with React
suspense. React Router v6 uses the `useTransition` hook at the root of your
component hierarchy. This lets us provide a smoother experience when user
interaction needs to interrupt a pending route transition, for example when they
click a link to another route while a previously-clicked link is still loading.
The `navigate` API is aware of the internal pending transition state and will
do a REPLACE instead of a PUSH onto the history stack, so the user doesn't end
up with pages in their history that never actually loaded.

*Note: You should still use a `<Redirect>` as part of your route config
(inside a `<Routes>`). This change is only necessary for `<Redirect>`s that are
used to navigate in response to user interaction.*

Aside from suspense compatibility, `navigate`, like `Link`, supports relative
navigation. For example:

```jsx
// assuming we are at `/stuff`
function SomeForm() {
let navigate = useNavigate()
return (

<form onSubmit={async (event) => {
  let newRecord = await saveDataFromForm(event.target)
  // you can build up the URL yourself
  navigate(\`/stuff/${newRecord.id}\`)
  // or navigate relative, just like Link
  navigate(\`${newRecord.id}\`)
}}>{/\* ... \*/}</form>

)
}
```

Rename `<Link component>` to `<Link as>`

This is a simple renaming of a prop to better align with the common practice of
other libraries in the React ecosystem including styled-components and Reach UI.

Get `StaticRouter` from `react-router-dom/server`

The `StaticRouter` component has moved into a new bundle:
`react-router-dom/server`.

```js
// change
import { StaticRouter } from 'react-router-dom';
// to
import { StaticRouter } from 'react-router-dom/server';
```

This change was made both to follow more closely the convention established by
the `react-dom` package and to help users understand better what a
`<StaticRouter>` is for and when it should be used (on the server).

What did we miss?

Despite my best attempts at being thorough (it took me 2 days to write this) I'm
sure I missed something. If you follow this upgrade guide and find it's missing
something, please let us know. We are happy to help you figure out what to do
with your v5 code to be able to upgrade and take advantage of all of the cool
stuff in v6.

If you don't understand the rationale for some of the decisions we've made,
please feel free to reach out directly to [me on
Twitter](https://twitter.com/mjackson) or
[Ryan](https://twitter.com/ryanflore... Let's talk about it!

Good luck 🤘

Migrating React Router v5 to v6
将 React Router v5迁移到 v6
Note: This document is still a work in progress! The migration process from
React Router v5 to v6 isn't yet as smooth as we would like it to be. We are
planning on backporting several of v6's new APIs to v5 to make it smoother, and
this guide will keep improving as we continue to gather feedback.

注意: 这个文档仍然是一个正在进行的工作! 从 react Router v5到 v6的迁移过程并不像我们希望的那样顺利。 我们正在计划将几个 v 6的新 api 后移到 v 5来使其更加流畅,随着我们不断收集反馈,本指南将继续改进。

React Router version 6 introduces several powerful new features, as well as
improved compatibility with the latest versions of React. It also introduces a
few breaking changes from version 5. This document is a comprehensive guide on
how to upgrade your v4/5 app to v6 while hopefully being able to ship as often
as possible as you go.

React Router version 6引入了一些强大的新特性,以及与 React 最新版本的兼容性改进。 它还介绍了版本5的一些突破性变化。 本文档是一个关于如何将 v4 / 5应用程序升级到 v6的全面指南,同时希望能够尽可能多地发货。

If you are just getting started with React Router or you'd like to try out v6 in
a new app, please see the Getting Started guide.

如果你刚刚开始使用 React Router,或者你想在新的应用程序中使用 v 6,请参阅入门指南。

The examples in this guide will show code samples of how you might have built
something in a v5 app, followed by how you would accomplish the same thing in
v6. There will also be an explanation of why we made this change and how it's
going to improve both your code and the overall user experience of people who
are using your app.

本指南中的示例将展示如何在 v5应用程序中构建东西的代码示例,接下来是如何在 v6中完成同样的事情。 我们也会解释为什么我们做了这个改变,以及它将如何改进你的代码和使用你的应用程序的用户的整体用户体验。

In general, the process looks like this:

一般来说,整个过程是这样的:

Upgrade to React v16.8 or greater 升级到 React v16.8或更高版本
Upgrade to React Router v5.1 升级到 React Router v 5.1
Use 使用<Route children> everywhere 无处不在
Use hooks instead of 用钩子代替withRouter and "floating" 还有”漂浮”<Route>s (that aren't 那不是
part of a 一部分<Switch>)
Upgrade to React Router v6 升级到 React Router v 6
Upgrade all 升级所有<Switch> elements to 元素到<Routes>
Update 更新<Link to> values 价值观
Update 更新<Route path> patterns 模式
Remove 移除<Route exact> and 及<Route strict> props 道具
Move 走开<Route sensitive> to containing 为了控制<Routes caseSensitive>
Consolidate your 巩固你的<Route>s into a nested config (optional) 放到一个嵌套的配置中(可选)
Use 使用navigate instead of 而不是history
Use 使用useNavigate hook instead of 用钩子代替useHistory
Use 使用<Navigate> instead of 而不是<Redirect> (outside of route configs) (路线之外)
No need to change 不需要改变<Redirect> directly inside 直接进去<Routes>
Use 使用useRoutes instead of 而不是react-router-config
Rename 重命名<Link component> to 到<Link as>
Get 去吧StaticRouter from 从react-router-dom/server
Upgrade to React v16.8
升级到 React v16.8
React Router v6 makes heavy use of React
hooks, so you'll need to be on React
16.8 or greater before attempting the upgrade to React Router v6. The good news
is that React Router v5 is compatible with React >= 15, so if you're on v5 (or
v4) you should be able to upgrade React without touching any of your router
code.

React Router v 6大量使用了 reactooks,因此在尝试升级 React Router v 6之前,您需要在 React 16.8或更高版本上。 好消息是 React Router v5与 React 15兼容,所以如果你使用 v5(或 v4) ,你应该能够升级 React 而不用接触任何路由器代码。

Once you've upgraded to React 16.8, you should deploy your app. Then you can
come back later and pick up where you left off.

一旦你升级到 React 16.8,你应该部署你的应用程序。 然后你可以稍后再回来继续你的工作。

Upgrade to React Router v5.1
升级到 React Router v 5.1
It will be easier to make the switch to React Router v6 if you upgrade to v5.1
first. In v5.1, we released an enhancement to the handling of <Route children>
elements that will help smooth the transition to v6. Instead of using and props, just use regular element everywhere and use hooks to access the router's internal state.

如果您首先升级到 v5.1,那么切换到 React Router v6会更容易。 在 v5.1中,我们对 route children 元素的处理进行了增强,这将有助于顺利过渡到 v6。 代替使用和道具,只是使用普通元素无处不在,并使用钩子访问路由器的内部状态。

// v4 and v5 before 5.1
function User({ id }) {
// ...
}

<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route

path="/users/:id"
render={
  ({ match }) => <User id={match.params.id} />
}

/>
</Switch>

// v5.1 preferred style
function User() {
let { id } = useParams();
// ...
}

<Switch>
<Route exact path="/"><Home /></Route>
<Route path="/about"><About /></Route>
{/ Can also use a named children prop /}
<Route path="/users/:id" children={<User />} />
</Switch>
You can read more about v5.1's hooks API and the rationale behind the move to
regular elements on our blog.

你可以在我们的博客上阅读更多关于 v 5.1的 hooks API 和迁移到常规元素背后的原理。

In general, React Router v5.1 (and v6) favors elements over components (or
"element types"). There are a few reasons for this, but we'll discuss more
further down when we discuss v6's <Route> API.

一般来说,React Router v5.1(和 v6)偏向于元素而不是组件(或“元素类型”)。 这里有一些原因,但是我们将在下一步讨论 v6的 route API 时进一步讨论。

When you use regular React elements you get to pass the props
explicitly. This helps with code readability and maintenance over time. If you
were using <Route render> to get a hold of the params, you can just
useParams inside your route component instead.

当您使用常规 React 元素时,您可以显式地传递提案。 随着时间的推移,这有助于代码的可读性和维护。 如果你使用 route render 来获取 params,你可以在你的 route 组件中使用 params。

Along with the upgrade to v5.1, you should replace any usage of withRouter
with hooks. You should also get rid of any "floating" <Route> elements that
are not inside a <Switch>. Again, the blog post about
v5.1 explains how to do this
in greater detail.

随着升级到 v5.1,您应该用钩子替换 wifterwith 的任何用法。 您还应该去掉任何不在 switch 内部的“浮动” route 元素。 同样,关于 v 5.1的博客文章详细解释了如何做到这一点。

In summary, to upgrade from v4/5 to v5.1, you should:

总之,要从 v4 / 5升级到 v5.1,您应该:

Use 使用<Route children> instead of 而不是<Route render> and/or 及 / 或<Route component>
props 道具
Use 使用our hooks API 我们的钩子 API to 到
access router state like the current location and params 访问路由器状态,比如当前位置和参数
Replace all uses of 更换所有用途withRouter with hooks 用钩子
Replace any 更换任何一个<Route>s that are not inside a 它们不在一个<Switch> with 与useRouteMatch,
or wrap them in a 或者把它们包起来<Switch>
Again, once your app is upgraded to v5.1 you should test and deploy it, and
pick this guide back up when you're ready to continue.

同样,一旦你的应用程序升级到 v 5.1版本,你就应该测试和部署它,当你准备好继续的时候再选择这个指南。

Upgrade to React Router v6
升级到 React Router v 6
Heads up: This is the biggest step in the migration and will probably take
the most time and effort.

注意: 这是迁移过程中最大的一步,可能会花费最多的时间和精力。

For this step, you'll need to install React Router v6. If you're managing
dependencies via npm:

对于这个步骤,你需要安装 React Router v 6. 如果你通过 npm 管理依赖项:

$ npm install react-router@6 react-router-dom@6

or, for a React Native app

$ npm install react-router@6 react-router-native@6
Upgrade all <Switch> elements to <Routes>
将所有 switch 元素升级为 routes
React Router v6 introduces a Routes component that is kind of like Switch,
but a lot more powerful. The main advantages of Routes over Switch are:

React Router v6引入了一个类似于 Switch 的 Routes 组件,但功能更强大。 与 Switch 相比,路线的主要优点是:

All 所有<Route>s and S 和<Link>s inside a 在一个<Routes> are relative. This leads to 是相对的。这导致了
leaner and more predictable code in 更精简和更可预测的代码<Route path> and 及<Link to>
Routes are chosen based on the best match instead of being traversed in order. 路由是根据最佳匹配而不是按顺序选择的
This avoids bugs due to unreachable routes because they were defined later 这样可以避免由于无法达到的路径导致的 bug,因为这些路径是在后面定义的
in your 在你的<Switch>
Routes may be nested in one place instead of being spread out in different 路由可以嵌套在一个地方,而不是分散在不同的地方
components. In small to medium sized apps, this lets you easily see all your 在小到中型的应用程序中,你可以很容易地看到你所有的应用程序
routes at once. In large apps, you can still nest routes in bundles that you 在大型应用程序中,你仍然可以将路由嵌套在捆绑包中
load dynamically via 通过React.lazy
In order to use v6, you'll need to convert all your <Switch> elements to
<Routes>. If you already made the upgrade to v5.1, you're halfway there.

为了使用 v6,您需要将所有 switch 元素转换为 routes。 如果你已经升级到了 v5.1,那么你已经完成了一半。

First, let's talk about relative routes and links in v6.

首先,让我们讨论 v6中的相对路线和链接。

Relative Routes and Links
相关路线及连结
In v5, you had to be very explicit about how you wanted to nest your routes and
links. In both cases, if you wanted nested routes and links you had to build the
<Route path> and <Link to> props from the parent route's match.url and
match.path properties. Additionally, if you wanted to nest routes, you had to
put them in the child route's component.

在 v 5中,你必须非常明确地说明你想如何嵌套你的路线和链接。 在这两种情况下,如果你想要嵌套的路由和链接,你必须从父路由的 match.url 和 match.path 属性中构建 route path 和 link to props。 此外,如果您想要嵌套路由,您必须将它们放在子路由的组件中。

// This is a React Router v5 app
import { BrowserRouter, Switch, Route, Link, useRouteMatch } from 'react-router-dom';

function App() {
return (

<BrowserRouter>
  <Switch>
    <Route exact path="/"><Home /></Route>
    <Route path="/users"><Users /></Route>
  </Switch>
</BrowserRouter>

);
}

function Users() {
// In v5, nested routes are rendered by the child component, so
// you have <Switch> elements all over your app for nested UI.
// You build nested routes and links using match.url and match.path.
let match = useRouteMatch();

return (

<div>
  <nav>
    <Link to={`${match.url}/me`}>My Profile</Link>
  </nav>

  <Switch>
    <Route path={`${match.path}/me`}><OwnUserProfile /></Route>
    <Route path={`${match.path}/:id`}><UserProfile /></Route>
  </Switch>
</div>

);
}
This is the same app in v6:

这是同一个应用程序在 v 6:

// This is a React Router v6 app
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

function App() {
return (

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="users/*" element={<Users />} />
  </Routes>
</BrowserRouter>

);
}

function Users() {
return (

<div>
  <nav>
    <Link to="me">My Profile</Link>
  </nav>

  <Routes>
    <Route path=":id" element={<UserProfile />} />
    <Route path="me" element={<OwnUserProfile />} />
  </Routes>
</div>

);
}
A few important things to notice about v6 in this example:

在这个例子中,关于 v 6需要注意一些重要的事情:

<Route path> and 及<Link to> are relative. This means that they 是相对的。这意味着他们
automatically build on the parent route's path and URL so you don't have to 自动构建在父路由的路径和 URL 上,这样你就不必
manually interpolate 手动插入match.url or 或match.path
<Route exact> is gone. Instead, routes with descendant routes (defined in 取而代之的是带有子代路由的路由(在
other components) use a trailing 其他组件)使用拖尾* in their path to indicate they match 表明他们是匹配的
deeply 深深地
You may put your routes in whatever order you wish and the router will 你可以把你的路由按照任何你希望的顺序和路由器将
automatically detect the best route for the current URL. This prevents bugs 自动检测当前 URL 的最佳路径。这可以防止错误
due to manually putting routes in the wrong order in a 由于手动把路线在错误的顺序在一个<Switch>
You may have also noticed that all <Route children> from the v5 app changed to
<Route element> in v6. Assuming you followed the upgrade steps to v5.1, this
should be as simple as moving your route element from the child position to a
named element prop (TODO: can we provide a codemod here?).

您可能也注意到了,所有的 route 子元素从 v5应用程序更改为 v6中的 route 元素。 假设您按照升级步骤升级到了 v5.1,那么这应该很简单,只需将 route 元素从子位置移动到命名元素 prop (TODO: 我们能在这里提供 codemod 吗?) .

Advantages of <Route element>
Route 元素的优点
In the section about upgrading to v5.1, I promised you we'd discuss the
advantages of using regular elements instead of components (or element types)
for rendering. Let's take a quick break from upgrading and talk about that now.

在关于升级到 v5.1的部分中,我向您保证,我们将讨论在渲染中使用常规元素而不是组件(或元素类型)的优点。 让我们暂停一下升级,现在来谈谈这个问题。

For starters, we see React itself taking the lead here with the }> API. The fallback prop takes a React element, not a
component. This lets you easily pass whatever props you want to your <Spinner>
from the component that renders it.

首先,我们看到 React 自己在这里使用} API 占据了领先地位。 后备支柱需要一个反应元素,而不是组合元素。 这使您可以轻松地将您想要的道具从呈现它的组件传递给您的 spinner。

Using elements instead of components means we don't have to provide a
passProps-style API so you can get the props you need to your elements. For
example, in a component-based API there is no good way to pass props to the
<Profile> element that is rendered when matches. Most React libraries who take this approach end
up with either an API like or use a render prop or higher-order component.

使用元素而不是组件意味着我们不必提供类似于 apassprops 的 API,这样您就可以得到需要的元素支持。 例如,在基于组件的 API 中,没有好的方法将 props 传递给在匹配时呈现的 profile 元素。 大多数采用这种方法的 React 库最终要么使用类似 API 的 API,要么使用渲染支持或高阶组件。

Also, I'm not sure if you noticed this but in v4 and v5, Route's rendering API
became rather large. It went something like this:

另外,我不确定你是否注意到了这一点,但在 v4和 v5中,Route 的呈现 api 变得相当大。 事情是这样的:

// Ah, this is nice and simple!
<Route path=":userId" component={Profile} />

// But wait, how do I pass custom props to the <Profile> element??
// Hmm, maybe we can use a render prop in those situations?
<Route
path=":userId"
render={routeProps => (

<Profile routeProps={routeProps} animate={true} />

)}
/>

// Ok, now we have two ways to render something with a route. :/

// But wait, what if we want to render something when a route
// doesn't match the URL, like a Not Found page? Maybe we
// can use another render prop with slightly different semantics?
<Route
path=":userId"
children={({ match }) => (

match ? (
  <Profile match={match} animate={true} />
) : (
  <NotFound />
)

)}
/>

// What if I want to get access to the route match, or I need
// to redirect deeper in the tree?
function DeepComponent(routeStuff) {
// got routeStuff, phew!
}
export default withRouter(DeepComponent);

// Well hey, now at least we've covered all our use cases!
// ... facepalm
At least part of the reason for this API sprawl was that React did not provide
any way for us to get the information from the <Route> to your route element,
so we had to invent clever ways to get both the route data and your own
custom props through to your elements: component, render props, passProps
higher-order-components ... until hooks came along!

这个 API 蔓延的部分原因至少是因为 React 没有为我们提供任何从 route 到 route 元素的信息的方式,所以我们必须发明聪明的方法来获得路由数据和自定义的道具到元素: 组件、渲染道具、 passProps-higher-order-components... 直到出现!

Now, the conversation above goes like this:

现在,上面的对话是这样的:

// Ah, nice and simple API. And it's just like the <Suspense> API!
// Nothing more to learn here.
<Route path=":userId" element={<Profile />} />

// But wait, how do I pass custom props to the <Profile>
// element? Oh ya, it's just an element. Easy.
<Route path=":userId" element={<Profile animate={true} />} />

// Ok, but how do I access the router's data, like the URL params
// or the current location?
function Profile({ animate }) {
let params = useParams();
let location = useLocation();
}

// But what about components deep in the tree?
function DeepComponent() {
// oh right, same as anywhere else
let navigate = useNavigate();
}

// Aaaaaaaaand we're done here.
Another important reason for using the element prop in v6 is that is reserved for nesting routes. This is one of people's favorite
features from v3 and @reach/router, and we're bringing it back in v6. Taking
the code in the previous example one step further, we can hoist all <Route>
elements into a single route config:

在 v6中使用元素 prop 的另一个重要原因是为筑巢路线保留了空间。 这是人们在 v3和@reach / router 中最喜欢的特性之一,我们将在 v6中将其带回。 把前面例子中的代码再往前推一步,我们可以把所有 route 元素放入一个单独的 route 配置中:

// This is a React Router v6 app
import { BrowserRouter, Routes, Route, Link, Outlet } from 'react-router-dom';

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>

);
}

function Users() {
return (

<div>
  <nav>
    <Link to="me">My Profile</Link>
  </nav>

  <Outlet />
</div>

)
}
This step is optional of course, but it's really nice for small to medium sized
apps that don't have thousands of routes.

这一步当然是可选的,但是对于那些没有成千上万条路线的中小型应用程序来说真的很不错。

Notice how <Route> elements nest naturally inside a <Routes> element. Nested
routes build their path by adding to the parent route's path. We didn't need a
trailing * on <Route path="users"> this time because when the routes are
defined in one spot the router is able to see all your nested routes.

注意 route 元素是如何自然地嵌套在 routes 元素中的。 Netedroutes 通过添加父路径来构建它们的路径。 这次我们不需要在 route path 上加一个尾随 * ,因为当路由在一个点上定义时,路由器可以看到你所有的嵌套路由。

You'll only need the trailing * when there is another <Routes> somewhere in
that route's descendant tree. In that case, the descendant <Routes> will match
on the portion of the pathname that remains (see the previous example for what
this looks like in practice).

只有当该路由的子代树中有另一个 routes 时,才需要尾随 * 。 在这种情况下,子代路径将匹配保留的路径名部分(请参阅前面的示例了解实践中的情况)。

When using a nested config, routes with children should render an <Outlet>
in order to render their child routes. This makes it easy to render layouts with
nested UI.

当使用嵌套配置时,带有子节点的路由应该呈现 outlet 以呈现其子节点路由。 这使得使用嵌套的 UI 来渲染布局变得很容易。

Note on <Route path> patterns
关于路径模式的注释
React Router v6 uses a simplified path format. <Route path> in v6 supports
only 2 kinds of placeholders: dynamic :id-style params and * wildcards. A

  • wildcard may be used only at the end of a path, not in the middle.

React Router v6使用了一种简化的路径格式。 V6中的 route path 只支持两种占位符: dynamic: id-style params 和 * 通配符。 通配符只能在路径的末尾使用,而不能在中间使用。

All of the following are valid route paths in v6:

以下所有路径都是 v 6中的有效路由路径:

/groups
/groups/admin
/users/:id
/users/:id/messages
/files/*
/files/:id/*
/files-*
The following RegExp-style route paths are not valid in v6:

下列 regexp 样式的路由路径在 v6中无效:

/users/:id?
/tweets/:id(d+)
/files/*/cat.jpg
We added the dependency on path-to-regexp in v4 to enable more advanced pattern
matching. In v6 we are using a simpler syntax that allows us to predictably
parse the path for ranking purposes. It also means we can stop depending on
path-to-regexp, which is nice for bundle size.

我们在 v4中添加了对路径到 regexp 的依赖,以支持更高级的图案匹配。 在 v6中,我们使用了一种更简单的语法,允许我们为了排序的目的可预测地解析路径。 这还意味着我们可以停止依赖于 path-to-regexp,这对于 bundle 大小来说很好。

If you were using any of path-to-regexp's more advanced syntax, you'll have to
remove it and simplify your route paths. If you were using the RegExp syntax to
do URL param validation (e.g. to ensure an id is all numeric characters) please
know that we plan to add some more advanced param validation in v6 at some
point. For now, you'll need to move that logic to the component the route
renders, and let it branch it's rendered tree after you parse the params.

如果您正在使用任何一种 path-to-regexp 的更高级语法,则必须删除它并简化路由路径。 如果您使用 RegExp 语法来进行 URL 参数验证(例如,为了确保 id 全部是数字字符) ,请知道我们计划在某个时候在 v6中添加一些更高级的参数验证。 现在,您需要将该逻辑移动到路由呈现的组件,并让它在解析参数之后分支它呈现的树。

If you were using <Route sensitive> you should move it to its containing
<Routes caseSensitive> prop. Either all routes in a <Routes> element are
case-sensitive or they are not.

如果你使用的是敏感路线,你应该把它移动到它的包含路线 cassensitive 道具。 Routes 元素中的所有路由都区分大小写或不区分大小写。

One other thing to notice is that all path matching in v6 ignores the trailing
slash on the URL. In fact, <Route strict> has been removed and has no effect
in v6. This does not mean that you can't use trailing slashes if you need
to. Your app can decide to use trailing slashes or not, you just can't
render two different UIs client-side at <Route path="edit"> and
<Route path="edit/">. You can still render two different UIs at those URLs,
but you'll have to do it server-side.

另一件需要注意的事情是,v6中的所有路径匹配都忽略 URL 上的拖动 / 斜杠。 事实上,route strict 已经被移除,并且在 v6中没有任何效果。 这并不意味着如果需要的话不能使用拖尾斜杠。 你的应用程序可以决定是否使用拖尾斜杠,你只是不能在 route path"edit"和 route path"edit /"上呈现两个不同的 ui 客户端。 您仍然可以在这些 url 中呈现两个不同的 ui,但是您必须在服务器端进行处理。

Note on <Link to> values
关于链接到值的说明
In v5, a <Link to> value that does not begin with / was ambiguous; it depends
on what the current URL is. For example, if the current URL is /users, a v5
<Link to="me"> would render a . However, if the current URL
has a trailing slash, like /users/, the same <Link to="me"> would render . This makes it difficult to predict how links will behave, so
in v5 we recommended that you build links from the root URL (using match.url)
and not use relative <Link to> values.

在 v5中,不以 / 开头的 link to value 含糊不清; 它取决于当前 URL 是什么。 例如,如果当前的 URL 是 / users,一个 v5链接 to"me"会呈现一个 href"/"。 然而,如果当前的 URL 后面有一个斜杠,比如 / users / ,那么链接"me"就会呈现。 这使得很难预测链接的行为,因此在 v5中,我们建议您从根 URL (使用 match.URL)构建链接,而不要使用相对链接到值。

React Router v6 fixes this ambiguity. In v6, a <Link to="me"> will always
render the same , regardless of the current URL.

React Router v6解决了这个问题。 在 v 6中,链接"me"永远会呈现相同的 href,不管当前的 URL 是什么。

For example, a <Link to="me"> that is rendered inside a <Route path="users">
will always render a link to /users/me, regardless of whether or not the
current URL has a trailing slash. If you'd like to link to /me instead, you
can go up one segment of the URL using .., like <Link to="../me">. The ..
basically means "remove one segment of the current URL", regardless of whether
it has a trailing slash or not. Of course, you can always <Link to="/me"> if
you'd like to use an absolute URL instead.

例如,在一个 route 路径中呈现的一个 link to"me"用户总是会呈现一个到 / users / me 的链接,不管当前的 URL 是否有尾部斜杠。 如果你想链接到 / me,你可以使用。 . 比如链接到” . . / me”。 这个。 . 基本上意味着“删除当前 URL 的一个片段” ,不管它是否有一个斜杠尾随。 当然,如果你想使用绝对网址,你可以随时链接到"/"。

It may help to think about the current URL as if it were a directory path on the
filesystem and <Link to> like the cd command line utility.

把当前的 URL 看作文件系统上的目录路径,把 link 看作 cd 命令行实用程序,可能会有所帮助。

// If the current URL is /app/dashboard (with or without
// a trailing slash)
<Link to="stats"> //
<Link to="../stats"> //

<Link to="../../stats"> //

<Link to="../../../stats"> //

// On the command line, if the current directory is /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
Note: The decision to ignore trailing slashes while matching and creating relative
paths was not taken lightly by our team. We consulted with a number of
our friends and clients (who are also our friends!) about it. We found that
most of us don't even understand how plain HTML relative links are handled
with the trailing slash. Most people guessed it worked like cd on the
command line (it does not). Also, HTML relative links don't have the concept of nested
routes, they only worked on the URL, so we had to blaze our own trail here a bit.
@reach/router set this precendent and it has worked out well for a couple of
years.

注意: 在匹配和创建相对路径时忽略拖尾斜杠的决定,我们的团队并没有掉以轻心。 我们咨询了一些朋友和客户(他们也是我们的朋友!) 关于它。 我们发现,我们中的大多数人甚至不知道如何用斜线尾部处理普通的 HTML 相对链接。 大多数人认为它在命令行上的工作方式类似于 cd (事实并非如此)。 另外,HTML 相关链接没有嵌套路由的概念,它们只对 URL 起作用,所以我们不得不在这里开辟自己的路径。 @ reach / 路由器设置了这个精确值,几年来效果很好。

Use useRoutes instead of react-router-config
使用 useRoutes 代替 react-router-config
All of the functionality from v5's react-router-config package has moved into
core in v6. If you prefer/need to define your routes as JavaScript objects
instead of using React elements, you're going to love this.

V5的 react-router-config 包中的所有功能都已经移动到了 v6的核心中。 如果您更喜欢 / 需要将路由定义为 JavaScript 对象,而不是使用 React 元素,那么您一定会喜欢它。

function App() {
let element = useRoutes([

// These are the same as the props you provide to <Route>
{ path: '/', element: <Home /> },
{ path: 'dashboard', element: <Dashboard /> },
{ path: 'invoices',
  element: <Invoices />,
  // Nested routes use a children property, which is also
  // the same as <Route>
  children: [
    { path: ':id', element: <Invoice /> },
    { path: 'sent', element: <SentInvoices /> }
  ]
},
// Redirects use a redirectTo property to
{ path: 'home', redirectTo: '/' },
// Not found routes work as you'd expect
{ path: '*', element: <NotFound /> }

]);

// The returned element will render the entire element
// hierarchy with all the appropriate context it needs
return element;
}
Routes defined in this way follow all of the same semantics as <Routes>. In
fact, <Routes> is really just a wrapper around useRoutes. Crazy, I know.

以这种方式定义的路由遵循与路由相同的语义。 事实上,routes 实际上只是一个围绕 useRoutes 的包装器。 我知道这很疯狂。

We encourage you to give both <Routes> and useRoutes a shot and decide for
yourself which one you prefer to use. Honestly, we like and use them both.

我们鼓励您给两个路由器和用户一个尝试,并决定自己喜欢使用哪一个。 老实说,我们喜欢并且使用它们。

If you had cooked up some of your own logic around data fetching and rendering
server-side, we have a low-level matchRoutes function available as well
similar to the one we had in react-router-config.

如果您已经在数据获取和渲染服务器端方面创建了一些自己的逻辑,那么我们就有了一个低级的 matchRoutes 函数,它与我们在 react-router-config 中使用的那个类似。

Use navigate instead of history
使用导航而不是历史
React Router v6 introduces a new navigation API that is synonymous with <Link>
and provides better compatibility with suspense-enabled apps. We include both
imperative and declarative versions of this API depending on your style and
needs.

React Router v6引入了一个新的导航 API,与 link 是同义词,并提供了与支持悬念的应用程序更好的兼容性。 根据您的样式和需要,我们包括这个 API 的命令式和声明式版本。

// This is a React Router v5 app
import { useHistory } from 'react-router-dom';

function App() {
let history = useHistory();
function handleClick() {

history.push('/home')

}
return (

<div>
  <button onClick={handleClick}>go home</button>
</div>

);
}
In v6, this app should be rewritten to use the navigate API. Most of the time
this means changing useHistory to useNavigate and changing the
history.push or history.replace callsite.

在 v 6中,应该重写这个应用程序来使用导航 API。 在大多数情况下,这意味着将 useHistory 更改为 useNavigate,并更改 history.push 或 history.replace callsite。

// This is a React Router v6 app
import { useNavigate } from 'react-router-dom';

function App() {
let navigate = useNavigate();
function handleClick() {

navigate('/home')

}
return (

<div>
  <button onClick={handleClick}>go home</button>
</div>

);
}
If you need to replace the current location instead of push a new one onto the
history stack, use navigate(to, { replace: true }). If you need state, use
navigate(to, { state }). You can think of the first arg to navigate as your
<Link to> and the other arg as the replace and state props.

如果需要替换当前位置而不是将新位置推送到历史堆栈,请使用导航(to,{ replace: true })。 如果需要状态,请使用导航(到,{ state })。 您可以将第一个导航参数视为链接到,而另一个参数视为替换和状态道具。

If you prefer to use a declarative API for navigation (ala v5's Redirect
component), v6 provides a Navigate component. Use it like:

如果您喜欢使用声明性 API 进行导航(ala v5的 Redirectcomponent) ,那么 v6提供了一个 Navigate 组件。 使用方法如下:

import { Navigate } from 'react-router-dom';

function App() {
return <Navigate to="/home" replace state={state} />;
}
If you're currently using go, goBack or goForward from useHistory to
navigate backwards and forwards, you should also replace these with navigate
with a numerical argument indicating where to move the pointer in the history
stack. For example, here is some code using v5's useHistory hook:

如果你目前正在使用 go,goBack 或 goForward 从 usedhistory tonavigate 向前和向后,你也应该用一个数字参数来代替这些导航,指示在历史堆栈中将指针移动到哪里。 例如,这里有一些使用 v 5的 useHistory 钩子的代码:

// This is a React Router v5 app
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>
</>

);
}
Here is the equivalent app with v6:

下面是与 v 6相当的应用程序:

// This is a React Router v6 app
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>
</>

);
}
Again, one of the main reasons we are moving from using the history API
directly to the navigate API is to provide better compatibility with React
suspense. React Router v6 uses the useTransition hook at the root of your
component hierarchy. This lets us provide a smoother experience when user
interaction needs to interrupt a pending route transition, for example when they
click a link to another route while a previously-clicked link is still loading.
The navigate API is aware of the internal pending transition state and will
do a REPLACE instead of a PUSH onto the history stack, so the user doesn't end
up with pages in their history that never actually loaded.

同样,我们从使用历史 API 直接导航 API 的一个主要原因是为了提供更好的与 React suspicion 的兼容性。 React Router v6在您的组件层次结构的根部使用 usetranion 钩子。 这让我们在用户交互需要中断挂起的路由转换时提供了一个更流畅的体验,例如,当用户点击另一条路由的链接时,之前点击的链接仍在加载。 导航 API 知道内部挂起的转换状态,并会执行 REPLACE 而不是 PUSH 到历史堆栈,因此用户不会在历史记录中出现从未实际加载过的页面。

Note: You should still use a <Redirect> as part of your route config
(inside a <Routes>). This change is only necessary for <Redirect>s that are
used to navigate in response to user interaction.

注意: 您仍然应该使用重定向作为您的路由配置的一部分(在路由中)。 此更改仅对于用于响应用户交互进行导航的重定向(redirect)而言是必要的。

Aside from suspense compatibility, navigate, like Link, supports relative
navigation. For example:

除了悬念兼容性,导航,像链接,支持相对性。例如:

// assuming we are at /stuff
function SomeForm() {
let navigate = useNavigate()
return (

<form onSubmit={async (event) => {
  let newRecord = await saveDataFromForm(event.target)
  // you can build up the URL yourself
  navigate(`/stuff/${newRecord.id}`)
  // or navigate relative, just like Link
  navigate(`${newRecord.id}`)
}}>{/* ... */}</form>

)
}
Rename <Link component> to <Link as>
将 link 组件重命名为 link
This is a simple renaming of a prop to better align with the common practice of
other libraries in the React ecosystem including styled-components and Reach UI.

这是一个简单的重命名道具,以便更好地与 React 生态系统中其他库(包括样式化组件和 Reach UI)的通用做法保持一致。

Get StaticRouter from react-router-dom/server
从 react-router-dom / server 获取 StaticRouter
The StaticRouter component has moved into a new bundle:
react-router-dom/server.

Staticrouter 组件已经移动到一个新的包中: react-router-dom / server。

// change
import { StaticRouter } from 'react-router-dom';
// to
import { StaticRouter } from 'react-router-dom/server';
This change was made both to follow more closely the convention established by
the react-dom package and to help users understand better what a
<StaticRouter> is for and when it should be used (on the server).

这个更改既是为了更加严格地遵循 react-dom 包建立的约定,也是为了帮助用户更好地理解 staticrouter 是用来干什么的,以及什么时候应该使用它(在服务器上)。

What did we miss?
我们错过了什么?
Despite my best attempts at being thorough (it took me 2 days to write this) I'm
sure I missed something. If you follow this upgrade guide and find it's missing
something, please let us know. We are happy to help you figure out what to do
with your v5 code to be able to upgrade and take advantage of all of the cool
stuff in v6.

尽管我尽了最大的努力去做到彻底(写这篇文章花了我两天时间) ,但我确信我遗漏了一些东西。 如果您遵循这个升级指南并且发现它缺少了什么,请让我们知道。 我们很乐意帮助您找出如何处理您的 v5代码,以便能够升级和利用 v6中所有酷的东西。

If you don't understand the rationale for some of the decisions we've made,
please feel free to reach out directly to me on
Twitter or
Ryan. Let's talk about it!

如果你不理解我们做出的一些决定的基本原理,请直接通过 Twitter 或 Ryan 与我联系。 我们来谈谈吧!

Good luck 🤘

祝你好运

阅读 1.4k

前端指北
关注devland团队「[链接]」,每天进步一点。

从事web开发多年,前端、后端、服务架构都有涉猎,经历过大公司、创业公司,擅长前端及公司技术选型。

6.9k 声望
624 粉丝
0 条评论

从事web开发多年,前端、后端、服务架构都有涉猎,经历过大公司、创业公司,擅长前端及公司技术选型。

6.9k 声望
624 粉丝
宣传栏