1 | import React from "react";
|
2 | import PropTypes from "prop-types";
|
3 | import warning from "tiny-warning";
|
4 |
|
5 | import RouterContext from "./RouterContext";
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | class 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 |
|
23 |
|
24 |
|
25 |
|
26 |
|
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 |
|
68 | if (__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 |
|
83 | export default Router;
|