diff --git a/modules/Link.js b/modules/Link.js index 2d409a23a1..3912890b85 100644 --- a/modules/Link.js +++ b/modules/Link.js @@ -54,6 +54,46 @@ var Link = React.createClass({ }; }, + getInitialState() { + var active = this.getActiveState(); + return { active }; + }, + + trySubscribe() { + var { history } = this.context; + if (!history) return; + this._unlisten = history.listen(this.handleHistoryChange); + }, + + tryUnsubscribe() { + if (!this._unlisten) return; + this._unlisten(); + this._unlisten = undefined; + }, + + handleHistoryChange() { + var { active } = this.state; + var nextActive = this.getActiveState(); + if (active !== nextActive) { + this.setState({ active: nextActive }); + } + }, + + getActiveState() { + var { history } = this.context; + var { to, query, onlyActiveOnIndex } = this.props; + if (!history) return false; + return history.isActive(to, query, onlyActiveOnIndex); + }, + + componentDidMount() { + this.trySubscribe(); + }, + + componentWillUnmount() { + this.tryUnsubscribe(); + }, + handleClick(event) { var allowTransition = true; var clickResult; @@ -83,7 +123,7 @@ var Link = React.createClass({ }, render() { - var { to, query, onlyActiveOnIndex } = this.props; + var { to, query } = this.props; var props = { ...this.props, @@ -91,13 +131,14 @@ var Link = React.createClass({ }; var { history } = this.context; + var { active } = this.state; // Ignore if rendered outside the context // of history, simplifies unit testing. if (history) { props.href = history.createHref(to, query); - if (history.isActive(to, query, onlyActiveOnIndex)) { + if (active) { if (props.activeClassName) props.className += props.className !== '' ? ` ${props.activeClassName}` : props.activeClassName; diff --git a/modules/__tests__/Link-test.js b/modules/__tests__/Link-test.js index a50ad2c460..a268000f50 100644 --- a/modules/__tests__/Link-test.js +++ b/modules/__tests__/Link-test.js @@ -225,6 +225,46 @@ describe('A ', function () { }); }); + describe('when route changes', function() { + it('changes active state', function(done) { + var LinkWrapper = React.createClass({ + shouldComponentUpdate() { + return false; + }, + render() { + return ( +
+ Link + {this.props.children} +
+ ); + } + }); + + var a, steps = [ + function () { + a = node.querySelector('a'); + expect(a.className).toEqual(''); + this.history.pushState(null, '/hello'); + }, + function () { + expect(a.className).toEqual('active'); + } + ]; + + var execNextStep = execSteps(steps, done); + + React.render(( + + + + + + + ), node, execNextStep); + }); + }); + describe('when clicked', function () { it('calls a user defined click handler', function (done) { var LinkWrapper = React.createClass({