路由仍然有效的原因是您在 PrivateRoute 组件上指定了一个 path 属性,这是 Switch 用于路径匹配的组件。
v5 评测Switchsource code:
/**
* The public API for rendering the first <Route> that matches.
*/
class Switch extends React.Component {
render() {
return (
<RouterContext.Consumer>
{context => {
invariant(context, "You should not use <Switch> outside a <Router>");
const location = this.props.location || context.location;
let element, match;
// We use React.Children.forEach instead of React.Children.toArray().find()
// here because toArray adds keys to all child elements and we do not want
// to trigger an unmount/remount for two <Route>s that render the same
// component at different URLs.
React.Children.forEach(this.props.children, child => {
if (match == null && React.isValidElement(child)) {
element = child;
const path = child.props.path || child.props.from;
match = path
? matchPath(location.pathname, { ...child.props, path })
: context.match;
}
});
return match
? React.cloneElement(element, { location, computedMatch: match })
: null;
}}
</RouterContext.Consumer>
);
}
}
Switch 遍历其子元素并检查 path 或 from 道具路径值,并计算匹配。对于计算出的匹配,它会克隆并返回匹配的element。
<ProtectedRoute
path="/movies/:id" // <-- child component path specified here
component={MovieForm}
/>
事实上,即使像 div 和 path 属性这样简单的东西也可以工作,例如:
<div path="/movies/:id">TEST</div>
这仅解释了Switch 内的匹配,但现在您想知道为什么PrivateRoute 渲染的Route 组件仍然有效。这是因为任何不是由Switch 直接渲染的Route 现在都被包含性地匹配和渲染(就好像它只在一个Router 组件中)。 Route 没有路径,因此它匹配 anything 并被渲染。
现在应该很明显Route 组件本身是无关紧要的。您可以稍微简化一下PrivateRoute;有条件地渲染一个 Route 与所有通过的路由道具,或 Redirect 到登录页面。
const ProtectedRoute = (props) => {
return auth.getCutterntUser()
? <Route {...props} />
: <Redirect to="/login" />;
};