React Router V6变化

官网:React Router
在进行项目时,遇到了React Router升级导致的问题,故特地找来官方API研究,但官方文档还未翻译,借助对V5的理解与翻译软件的帮助对官网的《Upgrading from v5》进行翻译记录。这一篇主要是记录React Router 版本变化,但由于个人开发经验所限,在记录的过程中省去了不熟悉的内容,详细的还是得参考官网。由于基本是把官网粗略的“翻译”了一下,故篇幅较多,而且问题不少,望指出我的不足之处。其中也有还没有实践过的内容。

总的来说,我能感知和理解的v6具体变化具体是以下四个:

  1. <Switch>替换为<Routes>
  2. <Route>的改变
  3. <Link>的改变
  4. <useHisttory>替换为<useNavigate>

一、 升级到 React v16.8

V6大量使用了React Hooks,所以需要使用 React 16.8 或更高版本。

二、从 React Router v5.1升级

可以平滑的过渡到V6

(一)、去除了<Switch>中的<Redirect>

如果想重定向,将<Redirect>移动到<Route rende> prop 中。

// 更改前
<Switch>
  <Redirect from="about" to="about-us" />
</Switch>

// 更改后
<Switch>
  <Route path="about" render={() => <Redirect to="about-us" />} />
</Switch>

不在<Switch>内的<Redirect>元素得到保留。他们将在V6中成为元素。

(二)、重构自定义<Route>

略。

三、升级到 React Router v6:

准备

先安装v6版:

$ npm install react-router-dom

(一)、将所有<Switch>升级到<Routes>

v6 引入了一个类似于Switch但更强大的组件Routes

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

在v5中,必须非常明确地说明希望如何嵌套路由和链接(nest routes and links)。在这两种情况下,如果想嵌套路由和链接(nested routes and links),则必须从父路由(parent route’s)的match.urlmatch.path属性构建<Route path><Link to>

此外,如果要嵌套路由(nest routes),则必须将它们放在子路由的组件中。

V5与V6对比:

V5与V6对比

在此示例中,有关 v6 需要注意的一些重要事项:

  • <Route path><Link to>是相对的。这意味着它们会自动在父路由的路径和URL上构建,因此不必手动插值或match.urlmatch.path
  • <Route exact>消失了。相反,具有后代路由(在其他组件中定义)的路由在其路径中使用一个尾随*符号来指示它们精确匹配
  • 可按照所需的任何顺序放置路由,路由器将自动检测当前URL的最佳路由。这可以防止由于手动将路由按错误的顺序放入<Switch>

注意: v5 应用中的所有<Route children>内容在 v6中都已更改为<Route element>

由此我们可以引出<Route element>的优点。

(二)、<Route element>的优点

在 v6 中使用element prop 的另一个重要原因是该<Route children>是为嵌套路由保留的。将上一示例中的代码更进一步,我们可以将所有<Route>元素提升到单个路由配置中:

更新对比:

// 此处没有变化
<Route path=":userId" component={Profile} />


// v4和v5
<Route
  path=":userId"
  render={routeProps => (
    <Profile routeProps={routeProps} animate={true} />
  )}
/>

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


<Route
  path=":userId"
  children={({ match }) => (
    match ? (
      <Profile match={match} animate={true} />
    ) : (
      <NotFound />
    )
  )}
/>

// v6为:
function Profile({ animate }) {
  let params = useParams();
  let location = useLocation();
}


// v4和v5
function DeepComponent(routeStuff) {
  // got routeStuff, phew!
}

// v6写法:
function DeepComponent() {
  // oh right, same as anywhere else
  let navigate = useNavigate();
}


export default withRouter(DeepComponent);

在 v6 中使用element prop 的另一个重要原因是是为嵌套路由保留的。这是人们最喜欢的 v3 和@reach/router 功能之一。将上一示例中的代码更进一步,我们可以将所有<Route>元素提升到单个路由配置中:

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>
  );
}

此步骤是可选的。

请注意<Route>元素如何自然地嵌套在<Routes>元素中。嵌套路由通过添加到父路由的路径来构建其路径。我们这次不需要在上尾随*,因为当routes在一个位置定义时,路由器能够看到所有嵌套的路由。``

只有当该路线的后代树中有另一个<Routes>位置时,您才需要尾随*。在这种情况下,后代<Routes>将在路径名中剩余的部分上进行匹配(有关这在实践中的外观,请参阅前面的示例)。

使用嵌套配置时,children路由应呈现<Outlet>以便呈现其子路由。这使得使用嵌套 UI 呈现布局变得容易。

(三)、关于<Route path>模式说明

v6 使用简化的路径格式。 <Route path>在 v6 中,支持 2 种占位符:

  1. 动态 :id 样式参数
  2. *通配符。*通配符只能在路径的末尾使用,不能在中间使用。

以下所有内容都是 v6 中的有效路由路径:

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

以下正则表达式样式的路由路径在 v6 中无效

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

**注意:**v6 中的所有路径匹配都会忽略 URL 上的尾随斜杠。实际上,<Route strict>已被删除,在 v6 中没有效果。这并不意味着如果需要,不能使用尾随斜杠。应用可以决定是否使用尾部斜杠,只是不能在<Route path='edit'><Route path='edit/'> 处呈现两个不同的 UI客户端。您仍然可以在这些URL上呈现两个不同的UI(但不建议这样做),但 必须 在服务器端执行此操作。

(四)、关于<Link to>模式说明

在 v5 中,不以\开头的值是模棱两可的;这取决于当前 URL 是什么。

例如,如果当前 URL 为/users ,则 v5 的<Link to='me'>将render成<a href='/me'> 。但是,如果当前 URL 具有尾部斜杠如/users/,则相同的<Link to='me'>将render为<a href='/users/me'>。这使得很难预测链接的行为方式,因此在 v5 中,建议从根(root) URL(使用match.url )构建链接,而不要使用相对<Link to>值。

V6修复了这种歧义。在 v6 中,无论当前 URL 如何,<Link to='me'>将始终render相同的<a href>

例如,在<Route path='users'>内呈现的<Link to='me'>将始终render一个指向</users/me>的链接,而不管当前 URL 是否具有尾随斜杠。

当想将"向上"链接回父路由时,请在<Link to>值中使用..前导段,类似于在<a href>操作。

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

function Users() {
  return (
    <div>
      <h2>
        {/* This links to /users - the current route */}
        <Link to=".">Users</Link>
      </h2>

      <ul>
        {users.map(user => (
          <li>
            {/* This links to /users/:id - the child route */}
            <Link to={user.id}>{user.name}</Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

function UserProfile() {
  return (
    <div>
      <h2>
        {/* This links to /users - the parent route */}
        <Link to="..">All Users</Link>
      </h2>

      <h2>
        {/* This links to /users/:id - the current route */}
        <Link to=".">User Profile</Link>
      </h2>

      <h2>
        {/* This links to /users/mj - a "sibling" route */}
        <Link to="../mj">MJ</Link>
      </h2>
    </div>
  );
}

将当前 URL 视为文件系统上的目录路径,<Link to>就像cd命令行实用程序一样。

// If your routes look like this
<Route path="app">
  <Route path="dashboard">
    <Route path="stats" />
  </Route>
</Route>

// and the current URL is /app/dashboard (with or without
// a trailing slash)
<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">

// 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

四、使用useRoutes替代react-router-config

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 /> }
      ]
    },
    // 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;
}

五、使用<useNavigate>替代<useHisttory>

v5版本写法:

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>
  );
}

在V6版本中,使用navigateAPI。大多数情况下,这意味着更改useHistoryuseNavigate并且更改history.pushhistory.replace

v6版本写法:

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

function App() {
  let navigate = useNavigate();
  function handleClick() {
    navigate("/home");
  }
  return (
    <div>
      <button onClick={handleClick}>go home</button>
    </div>
  );
}
  • 如果要替换当前位置,而不是将新位置推送到历史记录堆栈上,请使用navigate(to, { replace: true })
  • 如果需要state,请使用navigate(to, { state })

你可以把第一个参数<navigate>想象成<Link to>,其他的参数是replacestate

如果更喜欢使用声明性 API(declarative API)进行导航(navigation)(v5的Redirect组件),v6 提供一个<Navigate>组件。像这样使用:

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

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

注意(差异)

  • v5的<Redirect /> 默认使用replace逻辑,可通过pushprop 进行更改。
  • v6的<Navigate /> 默认使用push逻辑,可通过replace prop 进行更改。
// 过去写法:
<Redirect to="about" />
<Redirect to="home" push />

// v6写法:
<Navigate to="about" replace />
<Navigate to="home" />

实现来回导航(使用go、goBack、goForward)

简单来说,v5中从useHistory中使用go、goBack、goForward实现来回、指定跳转等,升级为只需要使用navigate

代码对比如下:

例如,下面是一些使用 v5 的useHistory钩子的代码:

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>
    </>
  );
}

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 中的<Redirect>元素作为路由配置的一部分(包含在<Routes>中)。如果需要立即重定向(redirect),可以

a方案:在服务器上执行此操作(可能是最佳解决方案)

b方案:在路由组件中render<Navigate>元素。但是,要认识到导航(navigation)将发生在useEffect中。

六、移除component prop

七、重命名<NavLink exact><NavLink end>

这是对 prop 的简单重命名,以便更好地与 React 生态系统中其他库的常见做法保持一致。

八、从中移除activeClassNameactiveStyle这两个props

变化:

可以通过一个函数,根据组件的活动状态自定义内联样式(style)或类字符串(className)。

<NavLink
  to="/messages"
- style={{ color: 'blue' }}
- activeStyle={{ color: 'green' }}
+ style={({ isActive }) => ({ color: isActive ? 'green' : 'blue' })}
>
  Messages
</NavLink>
<NavLink
  to="/messages"
- className="nav-link"
- activeClassName="activated"
+ className={({ isActive }) => "nav-link" + (isActive ? " activated" : "")}
>
  Messages
</NavLink>

九、Get StaticRouter from react-router-dom/server

链接:React Router | Upgrading from v5

十、ReplaceuseRouteMatchwithuseMatch

链接:React Router | Upgrading from v5

十一、<prompt>is not currently supported

链接:[React Router | Upgrading from v5](

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值