UNPKG

2.16 kBJavaScriptView Raw
1import React from "react";
2import PropTypes from "prop-types";
3import invariant from "tiny-invariant";
4import warning from "tiny-warning";
5
6import RouterContext from "./RouterContext.js";
7import matchPath from "./matchPath.js";
8
9/**
10 * The public API for rendering the first <Route> that matches.
11 */
12class Switch extends React.Component {
13 render() {
14 return (
15 <RouterContext.Consumer>
16 {context => {
17 invariant(context, "You should not use <Switch> outside a <Router>");
18
19 const location = this.props.location || context.location;
20
21 let element, match;
22
23 // We use React.Children.forEach instead of React.Children.toArray().find()
24 // here because toArray adds keys to all child elements and we do not want
25 // to trigger an unmount/remount for two <Route>s that render the same
26 // component at different URLs.
27 React.Children.forEach(this.props.children, child => {
28 if (match == null && React.isValidElement(child)) {
29 element = child;
30
31 const path = child.props.path || child.props.from;
32
33 match = path
34 ? matchPath(location.pathname, { ...child.props, path })
35 : context.match;
36 }
37 });
38
39 return match
40 ? React.cloneElement(element, { location, computedMatch: match })
41 : null;
42 }}
43 </RouterContext.Consumer>
44 );
45 }
46}
47
48if (__DEV__) {
49 Switch.propTypes = {
50 children: PropTypes.node,
51 location: PropTypes.object
52 };
53
54 Switch.prototype.componentDidUpdate = function(prevProps) {
55 warning(
56 !(this.props.location && !prevProps.location),
57 '<Switch> elements should not change from uncontrolled to controlled (or vice versa). You initially used no "location" prop and then provided one on a subsequent render.'
58 );
59
60 warning(
61 !(!this.props.location && prevProps.location),
62 '<Switch> elements should not change from controlled to uncontrolled (or vice versa). You provided a "location" prop initially but omitted it on a subsequent render.'
63 );
64 };
65}
66
67export default Switch;