diff --git a/examples/async-data/app.js b/examples/async-data/app.js index f37a1d119d..14f4d59a04 100644 --- a/examples/async-data/app.js +++ b/examples/async-data/app.js @@ -114,7 +114,7 @@ var Index = React.createClass({ var routes = ( - + ); diff --git a/modules/__tests__/Router-test.js b/modules/__tests__/Router-test.js index 8e59fa5287..db8161aace 100644 --- a/modules/__tests__/Router-test.js +++ b/modules/__tests__/Router-test.js @@ -198,10 +198,6 @@ describe('Router.run', function () { }); }); - describe('RouteHandler', function () { - it('throws if called after the router transitions to a new state'); - }); - describe('locations', function () { it('defaults to HashLocation', function (done) { var routes = diff --git a/modules/components/__tests__/RouteHandler-test.js b/modules/components/__tests__/RouteHandler-test.js index 8382e27e6b..11fd8bcca2 100644 --- a/modules/components/__tests__/RouteHandler-test.js +++ b/modules/components/__tests__/RouteHandler-test.js @@ -1,14 +1,72 @@ /** @jsx React.DOM */ - var assert = require('assert'); var expect = require('expect'); var React = require('react'); var Router = require('../../index'); var Route = require('../Route'); var RouteHandler = require('../RouteHandler'); +var TestLocation = require('../../locations/TestLocation'); +var { + Bar, + Foo +} = require('../../__tests__/TestHandlers'); + describe('RouteHandler', function () { + it('uses the old handler until the top-level component is rendered again', function (done) { + var updateComponentBeforeNextRender; + TestLocation.history = [ '/foo' ]; + + var Root = React.createClass({ + componentDidMount: function () { + updateComponentBeforeNextRender = function (cb) { + this.forceUpdate(cb); + }.bind(this); + }, + + render: function() { + return ( +
+

Root

+ +
+ ); + } + }); + + var routes = ( + + + + + ); + + var div = document.createElement('div'); + var steps = []; + + steps.push(function(Handler, state) { + React.render(, div, function () { + expect(div.innerHTML).toMatch(/Foo/); + TestLocation.push('/bar'); + }); + }); + + steps.push(function(Handler, state) { + updateComponentBeforeNextRender(function() { + expect(div.innerHTML).toMatch(/Foo/); + React.render(, div, function () { + expect(div.innerHTML).toMatch(/Bar/); + done(); + }); + }); + }); + + Router.run(routes, TestLocation, function () { + steps.shift().apply(this, arguments); + }); + }); + it('renders after an update', function (done) { var Nested = React.createClass({ componentDidMount: function () { diff --git a/modules/utils/createRouter.js b/modules/utils/createRouter.js index fb8abc0f88..6aa91cb463 100644 --- a/modules/utils/createRouter.js +++ b/modules/utils/createRouter.js @@ -138,6 +138,12 @@ function createRouter(options) { var onError = options.onError || defaultErrorHandler; var onAbort = options.onAbort || defaultAbortHandler; var state = {}; + var nextState = {}; + + function updateState() { + state = nextState; + nextState = {}; + } // Automatically fall back to full page refreshes in // browsers that don't support the HTML history API. @@ -302,11 +308,11 @@ function createRouter(options) { if (error || transition.isAborted) return callback.call(router, error, transition); - state.path = path; - state.action = action; - state.routes = nextRoutes; - state.params = nextParams; - state.query = nextQuery; + nextState.path = path; + nextState.action = action; + nextState.routes = nextRoutes; + nextState.params = nextParams; + nextState.query = nextQuery; callback.call(router, null, transition); }); @@ -327,7 +333,7 @@ function createRouter(options) { } else if (transition.isAborted) { onAbort.call(router, transition.abortReason, location); } else { - callback.call(router, router, state); + callback.call(router, router, nextState); } } @@ -384,10 +390,12 @@ function createRouter(options) { }, getInitialState: function () { + updateState(); return state; }, componentWillReceiveProps: function () { + updateState(); this.setState(state); },