React-router-dom 是专门用于web应用的路由解决方案。
1、Router、Link、Route
1.1、基本使用
首先编写一个简单的示例:
import React from "react";
import {
BrowserRouter as Router,
Route,
Link
} from "react-router-dom";
export default function App() {
return (
<div className="App">
<Router>
<Link to="/">首页</Link>
<Link to="/user">用户中心</Link>
<Link to="/login">登录</Link>
<Link to="/product/123">商品</Link>
<Route
path="/"
children={
() => HomePage({
data: "children" })}
component={
HomePage}
render={
() => <HomePage data="render" />}
/>
<Route path="/user" component={
UserPage} />
<Route path="/login" component={
LoginPage} />
</Router>
</div>
);
}
function HomePage(props) {
console.log("index", props);
return <div>首页 - {
props.data}</div>;
}
function UserPage(props) {
return <div>用户中心</div>;
}
function LoginPage(props) {
return <div>登录</div>;
}
示例中使用了 react-router-dom 的三个组件 BrowserRouter
、Route
、Link
。
Router 组件就好比路由器,Link 就是路由器的网线接口和网线,Route 就是和路由器连接的各种设备。
有了路由器,网线和设备才有存在的意义,所以 Route 和 Link 组件必须放在 Router 组件中。
Link 组件的 to 属性指定了点击该链接后会跳转的路由,Route 组件的 path 属性指定了该 Route 组件会匹配的路由,如果匹配上了就渲染 children
, component
, render
属性指定的组件(这三个属性都是用来指定待渲染组件的),三者区别如下:
children
即使路由不匹配也会渲染出指定的组件
component
只有路由匹配了才会渲染出指定组件,最好不要采用内联函数的方式传值,这样会导致每次重新渲染都会生成新的组件进行挂载,卸载之前的组件,而不是在之前组件上进行更新。如果要使用内联函数的形式,最好使用 render 或 children
render
适合传递内联函数,在路由匹配时执行该函数
三者的优先级为 children > component > render
1.2、源码实现
要想实现路由相关组件,我们需要借助一个库 history,这个库提供了一个方法 createBrowserHistory
,可以用来创建一个 history 对象,保存路由历史记录等信息,也可以监听路由变化。
1.2.1 Link 组件
先从最简单的开始,那就是 Link 组件,Link 组件的实质就是一个 a 标签
<Link to="/">首页</Link>
<Link to="/user">用户中心</Link>
<Link to="/login">登录</Link>
<Link to="/product/123">商品</Link>
import {
useContext } from "react";
import RouterContext from "./RouterContext";
export default function Link(props) {
const {
to, children } = props;
const context = useContext(RouterContext);
function onClick(e) {
// 阻止默认行为
e.preventDefault();
// 使用 Router 组件传递的 context 中的 history 对象来改变路由
context