React@16.x(46)路由v5.x(11)源码(3)- 实现 Router

发布于:2024-07-03 ⋅ 阅读:(16) ⋅ 点赞:(0)

1,Router 的结构

1,react-router 用于注入 history 上下文对象,但 history 对象是别人传递给它的。

2,react-router-dom 使用了 react-router,并传递创建 history 对象。

大致如下:

1,react-router-dom.js

import { createBrowserHistory } from "history"
import { Router } from "./react-router"

export default class BrowserRouter extends Component {
    history = createBrowserHistory(this.props)
    render() {
        return <Router history={this.history}>
            {this.props.children}
        </Router>
    }
}

2,react-router.js

export default class Router extends Component {
    ctxValue = { //上下文中对象
		history: {},
		location : {},
		match : {},
	}

    render() {
        return <ctx.Provider value={this.ctxValue}>
            {this.props.children}
        </ctx.Provider>
    }
}

3,其他组件使用:

import { BrowserRouter as Router } from "./react-router-dom";

export default function App() {
    return <Router></Router>
}

2,实现

项目目录

react-router
	-- index.js
	-- matchPath.js
	-- Router.js
	-- RouterContext.js
react-router-dom
	-- index.js
	-- BrowserRouter.js

2.1,react-router

1,matchPath.js

用于获取并组装 match 对象,参考 这篇文章

2,Router.js

import React, { Component } from "react";
import PropTypes from "prop-types";
import ctx from "./RouterContext";
import matchPath from "./matchPath";

export class Router extends Component {
    static propTypes = {
        history: PropTypes.object.isRequired,
        children: PropTypes.node,
    };

    state = {
        location: this.props.history.location, // location 作为状态,是因为切换路由时会发生变化。
    };

    componentDidMount() {
        this.unListen = this.props.history.listen((nextLocation, action) => {
            this.props.history.action = action;
            this.setState({
                location: nextLocation,
            });
        });
    }

    componentWillUnmount() {
        this.unListen();
    }

    ctxValue = {};

    render() {
        this.ctxValue.history = this.props.history;
        this.ctxValue.location = this.state.location;
        this.ctxValue.match = matchPath("/", this.state.location.pathname);
        return <ctx.Provider value={this.ctxValue}>{this.props.children}</ctx.Provider>;
    }
}

3,RouterContext.jsx

提供上下文对象。

import { createContext } from "react";

const context = createContext();
context.displayName = "Router"; // 在 React 插件调试时,显示的名字。

export default context;

4,index.jsx

export * from "./Router";

2.2,react-router-dom

BrowserRouter.jsx

import React, { Component } from "react";
import { createBrowserHistory } from "history";
import { Router } from "../react-router";

export class BrowserRouter extends Component {
    history = createBrowserHistory();
    render() {
        return <Router history={this.history}>{this.props.children}</Router>;
    }
}

index.jsx

export * from "./BrowserRouter";

接下文实现 Route


以上。