diff --git a/modules/Link.js b/modules/BaseLink.js similarity index 63% rename from modules/Link.js rename to modules/BaseLink.js index 6b3415f..8ccdd85 100644 --- a/modules/Link.js +++ b/modules/BaseLink.js @@ -1,9 +1,8 @@ import React, { Component, PropTypes } from 'react'; -class Link extends Component { +class BaseLink extends Component { constructor(props, context) { super(props, context); - this.router = context.router; this.isActive = this.isActive.bind(this); this.clickHandler = this.clickHandler.bind(this); @@ -13,7 +12,7 @@ class Link extends Component { } isActive() { - return this.router.isActive(this.props.routeName, this.props.routeParams); + return this.props.router.isActive(this.props.routeName, this.props.routeParams); } clickHandler(evt) { @@ -29,27 +28,15 @@ class Link extends Component { if (evt.button === 0 && !comboKey) { evt.preventDefault(); - this.router.navigate(this.props.routeName, this.props.routeParams, this.props.routeOptions); + this.props.router.navigate(this.props.routeName, this.props.routeParams, this.props.routeOptions); } } - routeChangeHandler(toState, fromState) { - this.setState({active: this.isActive()}); - } - - componentDidMount() { - this.router.addListener(this.routeChangeHandler); - } - - componentWillUnmount() { - this.router.removeListener(this.routeChangeHandler); - } - render() { - const { routeName, routeParams, className, activeClassName, children } = this.props; - const { active } = this.state; + const { router, routeName, routeParams, className, activeClassName, children } = this.props; - const href = this.router.buildUrl(routeName, routeParams); + const active = this.isActive(); + const href = router.buildUrl(routeName, routeParams); const linkclassName = (className ? className.split(' ') : []) .concat(active ? [activeClassName] : []).join(' '); @@ -59,11 +46,9 @@ class Link extends Component { } } -Link.contextTypes = { - router: PropTypes.object.isRequired -}; - Link.propTypes = { + // route: PropTypes.object.isRequired, + router: PropTypes.object.isRequired, routeName: PropTypes.string.isRequired, routeParams: PropTypes.object, routeOptions: PropTypes.object, @@ -79,4 +64,4 @@ Link.defaultProps = { routeOptions: {} }; -export default Link; +export default BaseLink; diff --git a/modules/index.js b/modules/index.js index a1583a6..8648e8c 100644 --- a/modules/index.js +++ b/modules/index.js @@ -1,9 +1,14 @@ -import Link from './Link'; +import BaseLink from './BaseLink'; import routeNode from './routeNode'; import RouterProvider from './RouterProvider'; +import withRoute from './withRoute'; -export default { - Link, +const Link = withRoute(BaseLink); + +export { + BaseLink, routeNode, - RouterProvider + RouterProvider, + withRoute, + Link }; diff --git a/modules/withRoute.js b/modules/withRoute.js new file mode 100644 index 0000000..801be79 --- /dev/null +++ b/modules/withRoute.js @@ -0,0 +1,42 @@ +import { Component, createElement } from 'react'; +import * as invariant from 'invariant'; + +function withRoute(BaseComponent) { + class ComponentWithRoute extends Component { + constructor(props, context) { + super(props, context); + this.router = context.router; + this.state = { + previousRoute: null, + route: this.router.getState() + }; + } + + componentDidMount() { + invariant( + this.router.registeredPlugins.LISTENERS, + '[react-router5] missing plugin router5-listeners.' + ); + + this.listener = (toState, fromState) => this.setState({ previousRoute: fromState, route: toState }); + this.router.addListener(this.nodeListener); + } + + componentWillUnmout() { + this.router.removeListener(this.listener); + } + + render() { + invariant( + !props.router && !props.route && !props.previousRoute, + '[react-router5] prop names `router`, `route` and `previousRoute` are reserved.' + ); + + return createElement(BaseComponent, { ...props, ...this.state, router: this.router }); + } + } + + return ComponentWithRoute; +} + +export default withRoute;