Router.js 2.0 KB

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