「前言」
react-router 工具库其实也没什么好写,毕竟只要有一点 React 基础肯定就知道或者使用过 react-router。今天阅读 react-router 源码的时候突然想到一些好玩的东西。
这篇文章我记录我自己的心路历程,从根源上理解 react-router。
「想象之中」
react 组件化的思想让开发者开发项目时就像拼「拼图🧩」一样,把多个组件拼接成一个项目。有些情况,我们只是在某个位置替换不同的组件,而不需要整个页面都重新加载。
举个例子🌰,常见的 CMS 系统布局,头部+左侧菜单栏都是固定的,变化的仅仅是右下内容区域。一种实现方式可以通过一种 state 状态来控制右下内容区域的需要渲染的内容组件,但是这种方式只能在当前 session 下可控,一旦刷新了页面,之前的 state 状态都会丢掉。显然对于一个项目来说这是不合理的。
浏览器的 URL 内容是一个很好的记录页面状态的信息。SPA 形式之前,不同的 URL 都会向服务器发送请求,然后服务器返回一个完整的 HTML 页面。 SPA 形式下,URL 路由的变化只会在 浏览器端处理,所以组装页面的任务就交给了浏览器。
此时 react-router 出现了,通过使用 react-router 以及阅读 react-router 源码,发现 react-router 不过就是基于 URL 内容变化的「智能拼图工具」。
「源码分析」
react-router 源码提供了 路由必需的基础组件,对于 web 应用还需要适配 react-router-dom,源码结构如下图。其中包含了包工程结构以及右边 react-router 导出的组件列表。
「简单例子」
import {
BrowserRouter,
Route,
Switch,
} from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
<Switch>
<Route path='/' exact={true} component={App1} />
<Route path='/app2' component={App1} />
<Route path='/app2' component={App2} />
<Route path='/app3' component={App3} />
</Switch>
</BrowserRouter>,
document.getElementById("root")
);
通过 简单例子 代码可以看出来 react-router 组件使用结构。<Route> 组件中包含需要渲染的业务组件,path属性决定什么情况渲染业务组件 。
最外层需要包裹一层 <BrowserRouter> 组件,从源码可以看出 Router 中嵌套了两层 React 的 Context:RouterContext 和 HistoryContext。
RouterContext 给子组件消费者提供了 「history」「location」「match」「staticContext」四个属性。
HistoryContext 提供给子组件消费者提供了「history」属性。
Route 组件的作用是从 Router 组件的上下文中解构出属性,并同时组装自己props属性,然后新建一个 RouterContext 上下文并将props传递给业务组件。
通过简单例子可以看出,从项目的入口列出 Route 列表,就是把整个页面当作一个拼图,然后通过路由替换整个页面。具体的业务组件中需要替换某一块区域,那么就在需要替换的地方列出 Route 列表。
「嵌套例子」
// src/App1.jsx
import React, { useState } from "react";
import { Layout, Menu } from "antd";
import { Route, Switch, Link } from "react-router-dom";
const { Header, Content, Sider, Footer } = Layout;
export default function App1({ routes = [] }) {
const [selecgtKey, setSelectKey] = useState([window.location.pathname]);
return (
...
<Content>
//核心代码
<Switch>
{routes.map((route, inx) => {
return (
<Route
key={inx}
path={route.path}
exact={route.exact}
render={() => <route.component routes={route.routes} />}
/>
);
})}
</Switch>
</Content>
...
);
}
嵌套代码只替换效果图中红框内容,只需要在 App1业务组件中再添加 <Route> 列表作为拼图占有区
路由会先匹配到外层父组件,然后再匹配父组件中Route组件。所以只要我想,我能一直套娃下去。
「路由用法」
-
所需 npm 包
npm install react-router
npm install react-router-dom
// 非必须
npm install react-router-config
「组件列表」
-
Router -
StaticRouter -
MemoryRouter -
HashRouter -
BrowserRouter -
NativeRouter
-
-
Switch -
Route -
Redirect -
Prompt -
Link -
NavLink
-
-
withRouter
「组件详情」
-
Router
属性 说明 history staticContext children -
BrowserRouter
属性 说明 basename forceRefresh getUserConfirmation keyLength children -
HashRouter
属性 说明 basename getUserConfirmation hashType children -
-
Route
属性 说明 path component render children exact strict sensitive location -
Switch
属性 说明 location children -
Redirect
属性 说明 push from to -
Prompt
属性 说明 when message -
Link
属性 说明 innerRef replace target to onClick -
NavLink (属性包含 Link )
属性 说明 activeClassName activeStyle className style exact isActive location sensitive strict -