Bootstrap

[email protected](47)路由v5.x(12)源码(4)- 实现 Route

1,原生 Route 的渲染内容

对如下代码来说:

import { BrowserRouter as Router, Route } from "react-router-dom";
function News() {
    return <div>News</div>;
}

function Goods() {
    return <div>Goods</div>;
}

export default function App() {
    return (
        <Router>
            <Route path="/page1" component={News}></Route>
            <Route path="/page2" component={Goods}></Route>
        </Router>
    );
}

React 插件展示的内容:

在这里插入图片描述

可以看到每个 Route 组件中,还会有一个 Router 上下文

这是因为,每个 Route 组件匹配的 match 对象不同,所以得再提供一次。除此之外,historylocation 这2个对象并没有发生变化。

2,实现

import React, { Component } from "react";
import ctx from "./RouterContext";
import matchPath from "./matchPath";

export class Route extends Component {
    renderChildren = (ctx) => {
        const { children, render, component } = this.props;
        // children 无论是否匹配都会渲染,也可以是函数,
        if (children !== undefined && children !== null) {
            if (typeof children === "function") {
                return children(ctx);
            } else {
                return children;
            }
        }

        // 没有匹配到路径,同时 children 没有内容
        if (!ctx.match) {
            return null;
        }

        // render 属性
        if (typeof render === "function") {
            return render(ctx);
        }

        // 只有 component 属性有值
        if (component) {
            const Comp = component;
            return <Comp {...ctx}></Comp>;
        }
        return null;
    };

    matchRoute = (pathname) => {
        const { path, exact = false, strict = false, sensitive = false } = this.props;
        return matchPath(path || "/", pathname, {
            exact,
            strict,
            sensitive,
        });
    };

    /**
     * 上下文消费者函数
     * Route 组件中又会提供一个 Router 的上下文,
     * history 和 location 对象相同,match 对象会重新进行匹配。
     */
    consumerFunc = (value) => {
        // 上下文对象定义在这里,当 Router 组件传递的上下文内容发生变化时,也会实时更新。
        const ctxValue = {
            history: value.location,
            location: value.location,
            match: this.matchRoute(value.location.pathname),
        };
        return <ctx.Provider value={ctxValue}>{this.renderChildren(ctxValue)}</ctx.Provider>;
    };
    render() {
        return <ctx.Consumer>{this.consumerFunc}</ctx.Consumer>;
    }
}

以上代码经过测试,和原生 Route 组件表现一致。


以上。

;