React Router V6变化

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

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

  1. 替换为
  2. 的改变
  3. 的改变
  4. 替换为

一、 升级到 React v16.8

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

二、从 React Router v5.1升级

可以平滑的过渡到V6

(一)、去除了中的

如果想重定向,将移动到 prop 中。

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

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

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

(二)、重构自定义

略。

三、升级到 React Router v6:

准备

先安装v6版:

$ npm install react-router-dom

(一)、将所有升级到

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

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

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

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

V5与V6对比:

React Router V6变化_第1张图片

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

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

注意: v5 应用中的所有内容在 v6中都已更改为

由此我们可以引出的优点。

(二)、的优点

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

更新对比:

// 此处没有变化
<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 功能之一。将上一示例中的代码更进一步,我们可以将所有元素提升到单个路由配置中:

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

此步骤是可选的。

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

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

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

(三)、关于模式说明

v6 使用简化的路径格式。 在 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 上的尾随斜杠。实际上,已被删除,在 v6 中没有效果。这并不意味着如果需要,不能使用尾随斜杠。应用可以决定是否使用尾部斜杠,只是不能在 处呈现两个不同的 UI客户端。您仍然可以在这些URL上呈现两个不同的UI(但不建议这样做),但 必须 在服务器端执行此操作。

(四)、关于模式说明

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

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

V6修复了这种歧义。在 v6 中,无论当前 URL 如何,将始终render相同的

例如,在内呈现的将始终render一个指向的链接,而不管当前 URL 是否具有尾随斜杠。

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

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 视为文件系统上的目录路径,就像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 
    { path: "/", element: <Home /> },
    { path: "dashboard", element: <Dashboard /> },
    {
      path: "invoices",
      element: <Invoices />,
      // Nested routes use a children property, which is also
      // the same as 
      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;
}

五、使用替代

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

你可以把第一个参数想象成,其他的参数是replacestate

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

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

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

注意(差异)

  • v5的 默认使用replace逻辑,可通过pushprop 进行更改。
  • v6的 默认使用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),可以

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

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

六、移除component prop

七、重命名

这是对 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

十一、is not currently supported

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

你可能感兴趣的:(前端,react.js,前端,react,router)