Skip to content

Commit

Permalink
[fixed] rendering current handlers before rendering root
Browse files Browse the repository at this point in the history
when the path changes, the router figures out the
next state, but we don't want the current views
using it until the root handler is rendered again,
allowing people to put up loading indicators, or
have live data not break their apps
  • Loading branch information
ryanflorence committed Nov 22, 2014
1 parent 0a01447 commit b75f648
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 12 deletions.
2 changes: 1 addition & 1 deletion examples/async-data/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ var Index = React.createClass({

var routes = (
<Route name="contacts" path="/" handler={App}>
<DefaultRoute handler={Index}/>
<DefaultRoute name="index" handler={Index}/>
<Route name="contact" path="contact/:id" handler={Contact}/>
</Route>
);
Expand Down
4 changes: 0 additions & 4 deletions modules/__tests__/Router-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <Route path="/" handler={Foo}/>
Expand Down
60 changes: 59 additions & 1 deletion modules/components/__tests__/RouteHandler-test.js
Original file line number Diff line number Diff line change
@@ -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 (
<div>
<h1>Root</h1>
<RouteHandler/>
</div>
);
}
});

var routes = (
<Route name="root" handler={Root} path='/'>
<Route name="foo" handler={Foo} path='/foo'/>
<Route name="bar" handler={Bar} path='/bar'/>
</Route>
);

var div = document.createElement('div');
var steps = [];

steps.push(function(Handler, state) {
React.render(<Handler/>, div, function () {
expect(div.innerHTML).toMatch(/Foo/);
TestLocation.push('/bar');
});
});

steps.push(function(Handler, state) {
updateComponentBeforeNextRender(function() {
expect(div.innerHTML).toMatch(/Foo/);
React.render(<Handler/>, 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 () {
Expand Down
20 changes: 14 additions & 6 deletions modules/utils/createRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
});
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -384,10 +390,12 @@ function createRouter(options) {
},

getInitialState: function () {
updateState();
return state;
},

componentWillReceiveProps: function () {
updateState();
this.setState(state);
},

Expand Down

0 comments on commit b75f648

Please sign in to comment.