Skip to content

Commit c6ed6fa

Browse files
committed
[removed] transition.wait, use callbacks instead
This commit also removes our dependency on when.js and introduces a callback argument in transition hooks. Users are expected to call callback(error) when they're finished doing async stuff. If they don't have a callback in their argument list, we automatically call the callback for them for backwards compat. Fixes #273 Fixes #631
1 parent a342d36 commit c6ed6fa

File tree

8 files changed

+65
-102
lines changed

8 files changed

+65
-102
lines changed

docs/api/components/RouteHandler.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@ Static Lifecycle Methods
1111
You can define static methods on your route handlers that will be called
1212
during route transitions.
1313

14-
### `willTransitionTo(transition, params, query)`
14+
### `willTransitionTo(transition, params, query, callback)`
1515

1616
Called when a handler is about to render, giving you the opportunity to
1717
abort or redirect the transition. You can pause the transition while you
18-
do some asynchonous work with `transition.wait(promise)`.
18+
do some asynchonous work and call `callback(error)` when you're done, or
19+
omit the callback in your argument list and it will be called for you.
1920

2021
See also: [transition](/docs/api/misc/transition.md)
2122

22-
### `willTransitionFrom(transition, component)`
23+
### `willTransitionFrom(transition, component, callback)`
2324

2425
Called when an active route is being transitioned out giving you an
2526
opportunity to abort the transition. The `component` is the current
@@ -34,13 +35,11 @@ See also: [transition](/docs/api/misc/transition.md)
3435
var Settings = React.createClass({
3536
statics: {
3637
willTransitionTo: function (transition, params) {
37-
return auth.isLoggedIn().then(function (loggedIn) {
38-
if (!loggedIn)
39-
return;
38+
if (!auth.isLoggedIn()) {
4039
transition.abort();
4140
auth.logIn({transition: transition});
4241
// in auth module call `transition.retry()` after being logged in
43-
});
42+
}
4443
},
4544

4645
willTransitionFrom: function (transition, component) {

modules/__tests__/Router-test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ describe('Router', function () {
3535
<Route path="/async" handler={Async}/>
3636
];
3737

38-
describe('transition.wait', function () {
39-
it('waits asynchronously in willTransitionTo', function (done) {
38+
describe('asynchronous willTransitionTo', function () {
39+
it('waits', function (done) {
4040
TestLocation.history = [ '/bar' ];
4141

4242
var div = document.createElement('div');
@@ -70,7 +70,7 @@ describe('Router', function () {
7070
});
7171
});
7272

73-
it('stops waiting asynchronously in willTransitionTo on location.pop', function (done) {
73+
it('stops waiting on location.pop', function (done) {
7474
TestLocation.history = [ '/bar' ];
7575

7676
var div = document.createElement('div');
@@ -106,7 +106,7 @@ describe('Router', function () {
106106
});
107107
});
108108

109-
it('stops waiting asynchronously in willTransitionTo on router.transitionTo', function (done) {
109+
it('stops waiting on router.transitionTo', function (done) {
110110
TestLocation.history = [ '/bar' ];
111111

112112
var div = document.createElement('div');
@@ -149,7 +149,7 @@ describe('Router', function () {
149149
});
150150
});
151151

152-
it('stops waiting asynchronously in willTransitionTo on router.replaceWith', function (done) {
152+
it('stops waiting on router.replaceWith', function (done) {
153153
TestLocation.history = [ '/bar' ];
154154

155155
var div = document.createElement('div');
@@ -597,7 +597,7 @@ describe('Router', function () {
597597
var Bar = React.createClass({
598598
statics: {
599599
willTransitionFrom: function (transition, component) {
600-
expect(div.querySelector('#bar')).toEqual(component.getDOMNode());
600+
expect(div.querySelector('#bar')).toBe(component.getDOMNode());
601601
done();
602602
}
603603
},

modules/__tests__/TestHandlers.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
var React = require('react');
22
var RouteHandler = require('../components/RouteHandler');
33
var State = require('../mixins/State');
4-
var delay = require('when/delay');
54

65
exports.Nested = React.createClass({
76
render: function () {
@@ -36,8 +35,8 @@ exports.Async = React.createClass({
3635
statics: {
3736
delay: 10,
3837

39-
willTransitionTo: function (transition) {
40-
transition.wait(delay(this.delay));
38+
willTransitionTo: function (transition, params, query, callback) {
39+
setTimeout(callback, this.delay);
4140
}
4241
},
4342

@@ -62,10 +61,11 @@ exports.RedirectToFooAsync = React.createClass({
6261
statics: {
6362
delay: 10,
6463

65-
willTransitionTo: function (transition) {
66-
transition.wait(delay(this.delay).then(function () {
64+
willTransitionTo: function (transition, params, query, callback) {
65+
setTimeout(function () {
6766
transition.redirect('/foo');
68-
}));
67+
callback();
68+
}, this.delay);
6969
}
7070
},
7171

@@ -91,10 +91,11 @@ exports.AbortAsync = React.createClass({
9191
statics: {
9292
delay: 10,
9393

94-
willTransitionTo: function (transition) {
95-
transition.wait(delay(this.delay).then(function () {
94+
willTransitionTo: function (transition, params, query, callback) {
95+
setTimeout(function () {
9696
transition.abort();
97-
}));
97+
callback();
98+
}, this.delay);
9899
}
99100
},
100101

modules/utils/Promise.js

Lines changed: 0 additions & 6 deletions
This file was deleted.

modules/utils/Transition.js

Lines changed: 38 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,5 @@
11
var assign = require('react/lib/Object.assign');
2-
var reversedArray = require('./reversedArray');
32
var Redirect = require('./Redirect');
4-
var Promise = require('./Promise');
5-
6-
/**
7-
* Runs all hook functions serially and calls callback(error) when finished.
8-
* A hook may return a promise if it needs to execute asynchronously.
9-
*/
10-
function runHooks(hooks, callback) {
11-
var promise;
12-
try {
13-
promise = hooks.reduce(function (promise, hook) {
14-
// The first hook to use transition.wait makes the rest
15-
// of the transition async from that point forward.
16-
return promise ? promise.then(hook) : hook();
17-
}, null);
18-
} catch (error) {
19-
return callback(error); // Sync error.
20-
}
21-
22-
if (promise) {
23-
// Use setTimeout to break the promise chain.
24-
promise.then(function () {
25-
setTimeout(callback);
26-
}, function (error) {
27-
setTimeout(function () {
28-
callback(error);
29-
});
30-
});
31-
} else {
32-
callback();
33-
}
34-
}
353

364
/**
375
* Calls the willTransitionFrom hook of all handlers in the given matches
@@ -40,23 +8,27 @@ function runHooks(hooks, callback) {
408
* Calls callback(error) when finished.
419
*/
4210
function runTransitionFromHooks(transition, routes, components, callback) {
43-
components = reversedArray(components);
44-
45-
var hooks = reversedArray(routes).map(function (route, index) {
46-
return function () {
47-
var handler = route.handler;
48-
49-
if (!transition.isAborted && handler.willTransitionFrom)
50-
return handler.willTransitionFrom(transition, components[index]);
51-
52-
var promise = transition._promise;
53-
transition._promise = null;
54-
55-
return promise;
11+
var runHooks = routes.reduce(function (callback, route, index) {
12+
return function (error) {
13+
if (error || transition.isAborted) {
14+
callback(error);
15+
} else if (route.handler.willTransitionFrom) {
16+
try {
17+
route.handler.willTransitionFrom(transition, components[index], callback);
18+
19+
// If there is no callback in the argument list, call it automatically.
20+
if (route.handler.willTransitionFrom.length < 3)
21+
callback();
22+
} catch (e) {
23+
callback(e);
24+
}
25+
} else {
26+
callback();
27+
}
5628
};
57-
});
29+
}, callback);
5830

59-
runHooks(hooks, callback);
31+
runHooks();
6032
}
6133

6234
/**
@@ -65,21 +37,27 @@ function runTransitionFromHooks(transition, routes, components, callback) {
6537
* handler. Calls callback(error) when finished.
6638
*/
6739
function runTransitionToHooks(transition, routes, params, query, callback) {
68-
var hooks = routes.map(function (route) {
69-
return function () {
70-
var handler = route.handler;
71-
72-
if (!transition.isAborted && handler.willTransitionTo)
73-
handler.willTransitionTo(transition, params, query);
74-
75-
var promise = transition._promise;
76-
transition._promise = null;
77-
78-
return promise;
40+
var runHooks = routes.reduceRight(function (callback, route) {
41+
return function (error) {
42+
if (error || transition.isAborted) {
43+
callback(error);
44+
} else if (route.handler.willTransitionTo) {
45+
try {
46+
route.handler.willTransitionTo(transition, params, query, callback);
47+
48+
// If there is no callback in the argument list, call it automatically.
49+
if (route.handler.willTransitionTo.length < 4)
50+
callback();
51+
} catch (e) {
52+
callback(e);
53+
}
54+
} else {
55+
callback();
56+
}
7957
};
80-
});
58+
}, callback);
8159

82-
runHooks(hooks, callback);
60+
runHooks();
8361
}
8462

8563
/**
@@ -93,7 +71,6 @@ function Transition(path, retry) {
9371
this.abortReason = null;
9472
this.isAborted = false;
9573
this.retry = retry.bind(this);
96-
this._promise = null;
9774
}
9875

9976
assign(Transition.prototype, {
@@ -112,10 +89,6 @@ assign(Transition.prototype, {
11289
this.abort(new Redirect(to, params, query));
11390
},
11491

115-
wait: function (value) {
116-
this._promise = Promise.resolve(value);
117-
},
118-
11992
from: function (routes, components, callback) {
12093
return runTransitionFromHooks(this, routes, components, callback);
12194
},

modules/utils/createRouter.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ function createRouter(options) {
322322
* all route handlers we're transitioning to.
323323
*
324324
* Both willTransitionFrom and willTransitionTo hooks may either abort or redirect the
325-
* transition. To resolve asynchronously, they may use transition.wait(promise). If no
325+
* transition. To resolve asynchronously, they may use the callback argument. If no
326326
* hooks wait, the transition is fully synchronous.
327327
*/
328328
dispatch: function (path, action, callback) {
@@ -374,7 +374,9 @@ function createRouter(options) {
374374
var transition = new Transition(path, this.replaceWith.bind(this, path));
375375
pendingTransition = transition;
376376

377-
transition.from(fromRoutes, components, function (error) {
377+
var fromComponents = components.slice(prevRoutes.length - fromRoutes.length);
378+
379+
transition.from(fromRoutes, fromComponents, function (error) {
378380
if (error || transition.isAborted)
379381
return callback.call(router, error, transition);
380382

modules/utils/reversedArray.js

Lines changed: 0 additions & 5 deletions
This file was deleted.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@
4747
"react": "0.12.x"
4848
},
4949
"dependencies": {
50-
"qs": "2.3.3",
51-
"when": "3.4.6"
50+
"qs": "2.3.3"
5251
},
5352
"tags": [
5453
"react",

0 commit comments

Comments
 (0)