UNPKG

2.07 kBJavaScriptView Raw
1import React from "react";
2import PropTypes from "prop-types";
3import warning from "tiny-warning";
4
5import RouterContext from "./RouterContext";
6
7/**
8 * The public API for putting history on context.
9 */
10class Router extends React.Component {
11 static computeRootMatch(pathname) {
12 return { path: "/", url: "/", params: {}, isExact: pathname === "/" };
13 }
14
15 constructor(props) {
16 super(props);
17
18 this.state = {
19 location: props.history.location
20 };
21
22 // This is a bit of a hack. We have to start listening for location
23 // changes here in the constructor in case there are any <Redirect>s
24 // on the initial render. If there are, they will replace/push when
25 // they mount and since cDM fires in children before parents, we may
26 // get a new location before the <Router> is mounted.
27 this._isMounted = false;
28 this._pendingLocation = null;
29
30 if (!props.staticContext) {
31 this.unlisten = props.history.listen(location => {
32 if (this._isMounted) {
33 this.setState({ location });
34 } else {
35 this._pendingLocation = location;
36 }
37 });
38 }
39 }
40
41 componentDidMount() {
42 this._isMounted = true;
43
44 if (this._pendingLocation) {
45 this.setState({ location: this._pendingLocation });
46 }
47 }
48
49 componentWillUnmount() {
50 if (this.unlisten) this.unlisten();
51 }
52
53 render() {
54 return (
55 <RouterContext.Provider
56 children={this.props.children || null}
57 value={{
58 history: this.props.history,
59 location: this.state.location,
60 match: Router.computeRootMatch(this.state.location.pathname),
61 staticContext: this.props.staticContext
62 }}
63 />
64 );
65 }
66}
67
68if (__DEV__) {
69 Router.propTypes = {
70 children: PropTypes.node,
71 history: PropTypes.object.isRequired,
72 staticContext: PropTypes.object
73 };
74
75 Router.prototype.componentDidUpdate = function(prevProps) {
76 warning(
77 prevProps.history === this.props.history,
78 "You cannot change <Router history>"
79 );
80 };
81}
82
83export default Router;