Router.js 2.2 KB

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