目录
- 1,原生 Switch 的渲染内容
- 2,实现
1,原生 Switch 的渲染内容
对如下代码来说:
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
function News() {
return <div className="page news">News</div>;
}
function Goods() {
return <div className="page goods">Goods</div>;
}
export default function App() {
return (
<Router>
<Switch>
<Route path="/page1" component={News}></Route>
<Route path="/page2" component={Goods}></Route>
</Switch>
</Router>
);
}
React 插件展示的内容:
可以看到,除了也使用了 Router 的上下文之外,只加载了一个 Route 组件。
2,实现
经测试,Switch
的子元素有如下规则:
- 如果不是
Route
组件,则会报错。 - 如果只有一个
Route
组件,则得到的props.children
的类型是对象。 - 如果有多个
Route
组件,则得到的props.children
的类型是数组。
所以,除了做以上特殊的判断外,再加上渲染第一个匹配到的组件的逻辑即可。
import React, { Component } from "react";
import ctx from "./RouterContext";
import { Route } from "./Route";
import matchPath from "./matchPath";
export class Switch extends Component {
getChildren = ({ location }) => {
let children = [];
if (Array.isArray(this.props.children)) {
children = this.props.children;
} else if (typeof this.props.children === "object") {
children = [this.props.children];
}
for (const child of children) {
if (child.type !== Route) {
throw new TypeError("子元素非 Route 组件");
}
const { path = "/", exact = false, strict = false, sensitive = false } = child.props;
const result = matchPath(path, location.pathname, {
exact,
strict,
sensitive,
});
if (result) {
return child;
}
}
return null;
};
render() {
return <ctx.Consumer>{this.getChildren}</ctx.Consumer>;
}
}
注意到,判断是否是 Route
组件,可通过引入的 Route
组件直接进行判断。
以上。