react-router-dom v6 与 v5的改动

878 阅读2分钟

1、<Switch> 标签更换成 <Routes>标签

含义:是唯一的因为它仅仅只会渲染一个路径。相比之下(不使用<Switch>包裹的情况下),每一个被location匹配到的将都会被渲染

2、 <Route>的新特性变更

component/renderelement替代

import Profile from './Profile';

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

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

3、<Redirect> 标签删除

解决方案:新版的路由需要引入<Navigate>标签

import { HashRouter as Router, Route, Routes, Navigate } from 'react-router-dom'
<Router>
    <Routes>
        <Route path='/login' element={<Login/>}/>
        <Route path='/admin' element={<Admin/>}/>
        <Route path="*" element={<Navigate to="/login" />} />
    </Routes>
</Router>

4、 嵌套路由变得更简单

  • <Route children> 已更改为接受子路由
  • <Route exact><Route strict>更简单的匹配规则。
  • <Route path> 路径层次更清晰。

1)简化嵌套路由定义

v5中的嵌套路由必须非常明确定义,且要求在这些组件中包含许多字符串匹配逻辑

// v5
import { BrowserRouter, Switch, Route, Link, useRouteMatch } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Switch>
        <Route path="/profile" component={Profile} />
      </Switch>
    </BrowserRouter>
  );
}

function Profile() {
  let { path, url } = useRouteMatch();

  return (
    <div>
      <Link to={`${url}/me`}>My Profile</Link>
      <Switch>
        <Route path={`${path}/me`}>
          <Me />
        </Route>
        <Route path={`${path}/:id`}>
          <Index />
        </Route>
      </Switch>
    </div>
  );
}


而在v6中,不需要任何useRouteMatch()

// v6
import { BrowserRouter, Routes, Route,  Link, } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="profile/*" element={<Profile/>} />
      </Routes>
    </BrowserRouter>
  );
}

function Profile() {
  return (
    <div>
        <Link to="me">My Profile</Link>
      <Routes>
        <Route path="me" element={<Me />} />
        <Route path=":id" element={<Index />} />
      </Routes>
    </div>
  );
}

2) 新API:Outlet

import { BrowserRouter, Routes, Route,  Link, } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="profile" element={<Profile />}>
          <Route path=":id" element={<MyProfile />} />
          <Route path="me" element={<OthersProfile />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

function Profile() {
  return (
    <div>
      <nav>
        <Link to="me">My Profile</Link>
      </nav>
        {/*
       将直接根据上面定义的不同路由参数,渲染<MyProfile /><OthersProfile />
        */}
      <Outlet />
    </div>
  )
}

3) 多个<Routes />

以前,我们只能 在React App中使用一个 Routes。但是现在我们可以在React App中使用多个路由,这将帮助我们基于不同的路由管理多个应用程序逻辑

import React from 'react';
import { Routes, Route } from 'react-router-dom';

function Dashboard() {
  return (
    <div>
      <p>Look, more routes!</p>
      <Routes>
        <Route path="/" element={<DashboardGraphs />} />
        <Route path="invoices" element={<InvoiceList />} />
      </Routes>
    </div>
  );
}

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="dashboard/*" element={<Dashboard />} />
    </Routes>
  );
}

5、 用useNavigate代替useHistory

// v5
import { useHistory } from 'react-router-dom';

function MyButton() {
  let history = useHistory();
  function handleClick() {
    history.push('/home');
  };
  return <button onClick={handleClick}>Submit</button>;
};

现在,history.push()将替换为navigate()

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

function MyButton() {
  let navigate = useNavigate();
  function handleClick() {
    navigate('/home');
  };
  return <button onClick={handleClick}>Submit</button>;
};

history的用法也将被替换成:

// v5
history.push('/home');
history.replace('/home');

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

6、新钩子useRoutes代替react-router-config

const App() => {
  const element = useRoutes([
  
    { path: 'login', element: <Login /> },
    { path: 'invoices',
      element: <Invoices />,
      children: [
        // useRoutes  可以使用index:true 来打开路由默认页面 
        { index: true, element: <Yeng /> },
        { path: ':id', element: <Invoice /> },
        { path: 'sent', element: <SentInvoices /> }
      ]
    },
    // 重定向 需要借助 `<Navigate>` 标签
    { path:'/', element: <Navigate to="/login" /> },
    // 404找不到
    { path: '*', element: <NotFound /> }
  ]);
  return element;
}

// useRoutes 第二个参数 字符串路由或者路由对象 路由对象必须包含pathname参数
useRoutes([], '/index') 
相当与 
useRoutes([{
  { path: '/index', element: <IndexBox />,},
  { index: true, element: <IndexBox /> }
}])

7、注意点

  • React Router v6使用简化的路径格,仅支持2种占位符:动态:id样式参数和*通配符
  • 以下都是v6中的有效路由路径:
/groups
/groups/admin
/users/:id
/users/:id/messages
/files/*
/files/:id/*
/files-*

  • 使用RegExp正则匹配的路径将无效:
/users/:id?
/tweets/:id(\d+)
/files/*/cat.jpg

  • v6中的所有路径匹配都将忽略URL上的尾部"/"。实际上,<Route strict>已被删除并且在v6中无效。这并不意味着您不需要使用斜杠。

  • v5版本之前的路径,存在路由歧义

    1. 当前路径:"/users",则<Link to="me">将跳转<a href="/me">
    2. 当前路径:"/users/",则<Link to="me">将跳转<a href="/users/me">
  • React Router v6修复了这种歧义,取消了尾部"/":

    1. 当前路径:"/users",则<Link to="me">将跳转<a href="/users/me">
    2. 当前路径:"/users",则<Link to="../me">将跳转<a href="/me">