个人react-router-dom源码学习系列第三篇 —— BrowserRouter组件

一、更新


[2019-4-21]

Fixed

  • 修复图片链接失效问题

Changed

  • 完善文章格式

二、前言


上一篇主要学习了官方的react-router-dom源码目录结构, 并且创建了我们自己的源码目录体系. 这一篇文章主要是一起学习BrowserRouter的源码, 并且使用.tsx完善自己的react-router-dom.

三、分析


BrowserRouter使用history库的createBrowserHistoryAPI, 通过传递给其的相关props, 创建history对象, 作为props传递给react-routerRouter组件, 源码是这样的:

1
2
3
4
5
6
7
8
...
// 创建history, 将history作为props传递至Router
history = createHistory(this.props);

render() {
return <Router history={this.history} children={this.props.children} />;
}
...

这里, 我们可以看到, 其实整个BrowserRouter源码里面, 最重要的就是如上的所示代码.

这里要特别注意的是, 源码中BrowserRouterHashRouter都只是对Router组件作了一层包装, 真正的路由顶层处理其实是在Router组件, 所以BrowserRouter似乎看起来不是很难懂…

四、实践


下面, 我们可以根据react-router-dom的思想, 来书写我们的BrowserRouter组件…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// src/yyg-react-router-dom/components/BrowserRouter.tsx

import * as React from 'react';
import {
History,
createBrowserHistory,
} from 'history';

import Router from './Router';


export interface IBrowserRouter {
children: React.ReactNode,

// ** createBrowserHistory的原汁原味props, 照写即可 **
basename?: string;
forceRefresh?: boolean;
keyLength?: number;
getUserConfirmation?: (
message: string,
callback: (result: boolean) => void,
) => void;
};


const BrowserRouter = React.memo<IBrowserRouter>((
props: IBrowserRouter,
): JSX.Element => {
const browserHistory: History = createBrowserHistory(props);

return (
<Router history={browserHistory} children={props.children} />
);
});


export default BrowserRouter;

照猫画虎完成了BrowserRouter组件, 这时候我们的项目应该是报错的, 因为我们的Router组件没有定义相关的props, 话不多说, 来到Router.tsx, 写入基本的测试代码, 测试对应的historyAPI是否正常传递.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// src/yyg-react-router-dom/components/Router.tsx

import * as React from 'react';
import {
History,
} from 'history';

export interface IRouterProps {
children: React.ReactNode;
history: History;
};


const Router = React.memo<IRouterProps>((
props: IRouterProps,
): JSX.Element => {

console.log(props); // { history: {...}, children: 'Route' }

return (
<div>Router&</div>
);
});

export default Router;

如果在Router组件中正常打印相关的内容, 则说明我们的BrowserRouter基本完成了…

五、源码


源码地址: 点我

六、总结


总而言之, BrowserRouter还算简单, 只是做了一层简单的封装, 下一篇主要学习一下Router组件, 这也是最重要的组件
!

PS: 每天进步一点点

最漆黑的那段路, 始终是要自己走完的