UNPKG

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