24

React-Router v6 新特性解读及迁移指南

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzA5NzkwNDk3MQ%3D%3D&%3Bmid=2650591529&%3Bidx=2&%3Bsn=1cfc5209c7fd4c591403a76175deae39
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

前言

18 年初, React Router 的主要开发人员创建一个名为 Reach Router 的轻量级替代方案。

原来是相互抗衡的,却没想 React Router 直接拿来合并(真香!) bmYnayE.jpg!web

目前 v6 已是测试最后一版,估计新的特性不出意外就是下面这些了: 2mQ3aei.jpg!web

  1. <Switch> 重命名为 <Routes>
  2. <Route> 的新特性变更。
  3. 嵌套路由变得更简单。

  4. useNavigate 代替 useHistory
  5. 新钩子 useRoutes 代替 react-router-config
  6. 大小减少:从 20kb8kb

1. <Switch> 重命名为 <Routes>

该顶级组件将被重命名。但是,其功能大部分保持不变(嗨,瞎折腾)。

// v5

<Switch>

<Route exact path="/"><Home /></Route>

<Route path="/profile"><Profile /></Route>

</Switch>


// v6

<Routes>

<Route path="/" element={<Home />} />

<Route path="profile/*" element={<Profile />} />

</Routes>

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. 嵌套路由变得更简单

具体变化有以下:

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

3.1 简化嵌套路由定义

v5 中的嵌套路由必须非常明确定义,且要求在这些组件中包含许多字符串匹配逻辑(活久见啊,终于意识到这个问题了。)

aYbauqF.jpg!web

且看之前的处理:

// v5

import {

BrowserRouter,

Switch,

Route,

Link,

useRouteMatch

} from 'react-router-dom';


function App() {

return (

<BrowserRouter>

<Switch>

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

<Route path="/profile" component={Profile} />

</Switch>

</BrowserRouter>

);

}


function Profile() {

let { path, url } = useRouteMatch();


return (

<div>

<nav>

<Link to={`${url}/me`}>My Profile</Link>

</nav>


<Switch>

<Route path={`${path}/me`}>

<MyProfile />

</Route>

<Route path={`${path}/:id`}>

<OthersProfile />

</Route>

</Switch>

</div>

);

}

而在 v6 中,你可以删除字符串匹配逻辑。不需要任何 useRouteMatch()

// v6

import {

BrowserRouter,

Routes,

Route,

Link,

Outlet

} from 'react-router-dom';


function App() {

return (

<BrowserRouter>

<Routes>

<Route path="/" element={<Home />} />

<Route path="profile/*" element={<Profile/>} />

</Routes>

</BrowserRouter>

);

}


function Profile() {

return (

<div>

<nav>

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

</nav>


<Routes>

<Route path="me" element={<MyProfile />} />

<Route path=":id" element={<OthersProfile />} />

</Routes>

</div>

);

}

当然,还有更酸爽的操作,直接在路由里定义 <Route><Route> ,然后用接下来的一个新 APIOutlet

3.2 新 API : Outlet

这玩意儿,像极了 {this.props.children} ,具体用法看以下例子:

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

);

}

4. 用 useNavigate 代替 useHistory

从一目了然改到双目失明。。。

总感觉 React Router 团队有点儿戏。。。

// 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() 将替换为 navigation()

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

7ruQfyb.jpg!web强行达成共识

5. 新钩子 useRoutes 代替 react-router-config

感觉又是一波强行 hooks ,但还是相对于之前简洁了一些。。。

function App() {

let element = useRoutes([

{ path: '/', element: <Home /> },

{ path: 'dashboard', element: <Dashboard /> },

{ path: 'invoices',

element: <Invoices />,

children: [

{ path: ':id', element: <Invoice /> },

{ path: 'sent', element: <SentInvoices /> }

]

},

// 重定向

{ path: 'home', redirectTo: '/' },

// 404找不到

{ path: '*', element: <NotFound /> }

]);

return element;

}

6. 大小减少:从 20kb8kb

React Router v6 给我们带来方便的同时,还把包减少了一半以上的体积。。。

EBry2uQ.jpg!web

感觉可以去看一波源码了。。。

关于奇舞周刊

《奇舞周刊》是360公司大前端团队「 奇舞团 」运营的前端技术社区。关注公众号后,直接发送链接到后台即可给我们投稿。

fI773i6.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK