Skip to content

Commit ec523e4

Browse files
authored
Add Promise support to async route functions (#3719)
* Add Promise support in getComponent(s). * Add Promises to get(Child/Index)Routes. * Chain getComponents default export handling too. * Point out that it's actually Babel 6 that's doing it. * Don't swallow exceptions. * Add babel-polyfill for Promises in tests. * Remove .default convenience on Promise handlers.
1 parent 7bb88c2 commit ec523e4

File tree

7 files changed

+75
-3
lines changed

7 files changed

+75
-3
lines changed

modules/PromiseUtils.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function isPromise(obj) {
2+
return obj && typeof obj.then === 'function'
3+
}

modules/__tests__/Router-test.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,23 @@ describe('Router', function () {
391391
})
392392
})
393393

394+
it('should support getComponent returning a Promise', function (done) {
395+
const Component = () => <div />
396+
397+
const getComponent = () => new Promise(resolve => resolve(Component))
398+
399+
render((
400+
<Router history={createHistory('/')} render={renderSpy}>
401+
<Route path="/" getComponent={getComponent} />
402+
</Router>
403+
), node, function () {
404+
setTimeout(function () {
405+
expect(componentSpy).toHaveBeenCalledWith([ Component ])
406+
done()
407+
})
408+
})
409+
})
410+
394411
})
395412

396413
describe('error handling', function () {

modules/__tests__/matchRoutes-test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,34 @@ describe('matchRoutes', function () {
290290
describeRoutes()
291291
})
292292

293+
describe('a Promise-based route config', function () {
294+
function makeAsyncRouteConfig(routes) {
295+
routes.forEach(function (route) {
296+
const { childRoutes, indexRoute } = route
297+
298+
if (childRoutes) {
299+
delete route.childRoutes
300+
301+
route.getChildRoutes = () => new Promise(resolve => resolve(childRoutes))
302+
303+
makeAsyncRouteConfig(childRoutes)
304+
}
305+
306+
if (indexRoute) {
307+
delete route.indexRoute
308+
309+
route.getIndexRoute = () => new Promise(resolve => resolve(indexRoute))
310+
}
311+
})
312+
}
313+
314+
beforeEach(function () {
315+
makeAsyncRouteConfig(routes)
316+
})
317+
318+
describeRoutes()
319+
})
320+
293321
describe('an asynchronous JSX route config', function () {
294322
let getChildRoutes, getIndexRoute, jsxRoutes
295323

modules/getComponents.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { mapAsync } from './AsyncUtils'
2+
import { isPromise } from './PromiseUtils'
23

34
function getComponentsForRoute(nextState, route, callback) {
45
if (route.component || route.components) {
@@ -8,7 +9,13 @@ function getComponentsForRoute(nextState, route, callback) {
89

910
const getComponent = route.getComponent || route.getComponents
1011
if (getComponent) {
11-
getComponent.call(route, nextState, callback)
12+
const componentReturn = getComponent.call(route, nextState, callback)
13+
if (isPromise(componentReturn))
14+
componentReturn
15+
.then(
16+
component => callback(null, component),
17+
callback
18+
)
1219
} else {
1320
callback()
1421
}

modules/matchRoutes.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { loopAsync } from './AsyncUtils'
2+
import { isPromise } from './PromiseUtils'
23
import { matchPattern } from './PatternUtils'
34
import warning from './routerWarning'
45
import { createRoutes } from './RouteUtils'
@@ -18,7 +19,7 @@ function getChildRoutes(route, location, paramNames, paramValues, callback) {
1819
params: createParams(paramNames, paramValues)
1920
}
2021

21-
route.getChildRoutes(partialNextState, (error, childRoutes) => {
22+
const childRoutesReturn = route.getChildRoutes(partialNextState, (error, childRoutes) => {
2223
childRoutes = !error && createRoutes(childRoutes)
2324
if (sync) {
2425
result = [ error, childRoutes ]
@@ -28,6 +29,13 @@ function getChildRoutes(route, location, paramNames, paramValues, callback) {
2829
callback(error, childRoutes)
2930
})
3031

32+
if (isPromise(childRoutesReturn))
33+
childRoutesReturn
34+
.then(
35+
childRoutes => callback(null, createRoutes(childRoutes)),
36+
callback
37+
)
38+
3139
sync = false
3240
return result // Might be undefined.
3341
}
@@ -41,9 +49,16 @@ function getIndexRoute(route, location, paramNames, paramValues, callback) {
4149
params: createParams(paramNames, paramValues)
4250
}
4351

44-
route.getIndexRoute(partialNextState, (error, indexRoute) => {
52+
const indexRoutesReturn = route.getIndexRoute(partialNextState, (error, indexRoute) => {
4553
callback(error, !error && createRoutes(indexRoute)[0])
4654
})
55+
56+
if (isPromise(indexRoutesReturn))
57+
indexRoutesReturn
58+
.then(
59+
indexRoute => callback(null, createRoutes(indexRoute)[0]),
60+
callback
61+
)
4762
} else if (route.childRoutes) {
4863
const pathless = route.childRoutes.filter(childRoute => !childRoute.path)
4964

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"babel-plugin-add-module-exports": "^0.2.1",
5151
"babel-plugin-dev-expression": "^0.2.1",
5252
"babel-plugin-istanbul": "^1.0.3",
53+
"babel-polyfill": "^6.13.0",
5354
"babel-preset-es2015": "^6.13.2",
5455
"babel-preset-react": "^6.11.1",
5556
"babel-preset-stage-1": "^6.13.0",

tests.webpack.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-env mocha */
22

3+
import 'babel-polyfill'
34
import expect from 'expect'
45

56
import { _resetWarned } from './modules/routerWarning'

0 commit comments

Comments
 (0)