diff --git a/modules/AsyncProps.js b/modules/AsyncProps.js index 4c95c74..46e6c9f 100644 --- a/modules/AsyncProps.js +++ b/modules/AsyncProps.js @@ -8,6 +8,14 @@ function last(arr) { return arr[arr.length - 1] } +/** + * We need to iterate over all components for specified routes. + * Components array can include objects if named components are used: + * https://github.com/rackt/react-router/blob/latest/docs/API.md#named-components + * + * @param components + * @param iterator + */ function eachComponents(components, iterator) { for (var i = 0, l = components.length; i < l; i++) { if (typeof components[i] === 'object') { @@ -29,7 +37,11 @@ function filterAndFlattenComponents(components) { return flattened } -function loadAsyncProps(components, params, cb) { +function defaultResolver(Component, params, cb) { + Component.loadProps(params, cb) +} + +function loadAsyncProps(components, params, cb, resolver = defaultResolver) { // flatten the multi-component routes let componentsArray = [] let propsArray = [] @@ -46,7 +58,7 @@ function loadAsyncProps(components, params, cb) { } components.forEach((Component, index) => { - Component.loadProps(params, (error, props) => { + resolver(Component, params, (error, props) => { needToLoadCounter-- propsArray[index] = props componentsArray[index] = Component @@ -112,7 +124,7 @@ function createElement(Component, props) { return } -export function loadPropsOnServer({ components, params }, cb) { +export function loadPropsOnServer({ components, params, resolver }, cb) { loadAsyncProps( filterAndFlattenComponents(components), params, @@ -125,7 +137,8 @@ export function loadPropsOnServer({ components, params }, cb) { const scriptString = `` cb(null, propsAndComponents, scriptString) } - } + }, + resolver ) } @@ -189,6 +202,7 @@ class AsyncProps extends React.Component { location: object.isRequired, onError: func.isRequired, renderLoading: func.isRequired, + resolver: func, // server rendering propsArray: array, @@ -303,7 +317,8 @@ class AsyncProps extends React.Component { prevProps: null }) } - }) + }), + this.props.resolver ) } diff --git a/modules/__tests__/AsyncProps-test.js b/modules/__tests__/AsyncProps-test.js index 3927aa8..2bdd0de 100644 --- a/modules/__tests__/AsyncProps-test.js +++ b/modules/__tests__/AsyncProps-test.js @@ -395,6 +395,33 @@ describe('AsyncProps', () => { /> ), div, next) }) + + it('allows to override resolver function', (done) => { + const appSpy = spyOn(App, 'loadProps').andCallThrough() + + const next = execNext([ + () => {}, + () => { + expect(appSpy.calls.length).toEqual(1) + expect(appSpy.calls[0].arguments[2]).toEqual('check') + }, + done + ]) + + function resolver(Component, params, cb) { + Component.loadProps(params, cb, 'check') + } + + App.setAssertions(next) + + render(( + } + /> + ), div, next) + }) }) describe('server rendering', () => { @@ -420,6 +447,24 @@ describe('AsyncProps', () => { }) }) + it('allows to override resolver function', (done) => { + const appSpy = spyOn(App, 'loadProps').andCallThrough() + function resolver(Component, params, cb) { + Component.loadProps(params, cb, 'check') + } + const loadPropsRoutes = { + path: '/', + component: App + } + match({ routes: loadPropsRoutes, location: '/' }, (err, redirect, renderProps) => { + loadPropsOnServer({ ...renderProps, resolver }, () => { + expect(appSpy.calls.length).toEqual(1) + expect(appSpy.calls[0].arguments[2]).toEqual('check') + done() + }) + }) + }) + it('renders synchronously with props from hydration', () => { const html = renderToString(