Skip to content

Commit

Permalink
Merge pull request #342 from stevoland/deferred
Browse files Browse the repository at this point in the history
Support fetchDataDeferred
  • Loading branch information
erikras committed Oct 14, 2015
2 parents 57b0534 + 9d96a8e commit c292c29
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 15 deletions.
9 changes: 5 additions & 4 deletions src/containers/Widgets/Widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Widgets extends Component {
editStart: PropTypes.func.isRequired
}

static fetchData(getState, dispatch) {
static fetchDataDeferred(getState, dispatch) {
if (!isLoaded(getState())) {
return dispatch(loadWidgets());
}
Expand Down Expand Up @@ -56,9 +56,10 @@ class Widgets extends Component {
</h1>
<DocumentMeta title="React Redux Example: Widgets"/>
<p>
This data was loaded from the server before this route was rendered. If you hit refresh on your browser, the
data loading will take place on the server before the page is returned. If you navigated here from another
page, the data was fetched from the client.
If you hit refresh on your browser, the data loading will take place on the server before the page is returned.
If you navigated here from another page, the data was fetched from the client after the route transition.
This uses the static method <code>fetchDataDeferred</code>. To block a route transition until some data is loaded, use <code>fetchData</code>.
To always render before loading data, even on the server, use <code>componentDidMount</code>.
</p>
<p>
This widgets are stored in your session, so feel free to edit it and refresh.
Expand Down
78 changes: 78 additions & 0 deletions src/helpers/__tests__/getDataDependencies-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { expect } from 'chai';
import React from 'react';
import { div } from 'react-dom';
import getDataDependencies from '../getDataDependencies';

describe('getDataDependencies', () => {
let getState;
let dispatch;
let location;
let params;
let CompWithFetchData;
let CompWithNoData;
let CompWithFetchDataDeferred;
let ConnectedCompWithFetchData;
let ConnectedCompWithFetchDataDeferred;

beforeEach(() => {
getState = 'getState';
dispatch = 'dispatch';
location = 'location';
params = 'params';

CompWithNoData = () =>
<div />;

CompWithFetchData = () =>
<div />;

CompWithFetchData.fetchData = (_getState, _dispatch, _location, _params) => {
return `fetchData ${_getState} ${_dispatch} ${_location} ${_params}`;
};
CompWithFetchDataDeferred = () =>
<div />;

CompWithFetchDataDeferred.fetchDataDeferred = (_getState, _dispatch, _location, _params) => {
return `fetchDataDeferred ${_getState} ${_dispatch} ${_location} ${_params}`;
};

ConnectedCompWithFetchData = () =>
<div/>;

ConnectedCompWithFetchData.WrappedComponent = CompWithFetchData;

ConnectedCompWithFetchDataDeferred = () =>
<div/>;

ConnectedCompWithFetchDataDeferred.WrappedComponent = CompWithFetchDataDeferred;
});

it('should get fetchDatas', () => {
const deps = getDataDependencies([
CompWithFetchData,
CompWithNoData,
CompWithFetchDataDeferred,
ConnectedCompWithFetchData,
ConnectedCompWithFetchDataDeferred
], getState, dispatch, location, params);

expect(deps).to.deep.equal([
'fetchData getState dispatch location params',
'fetchData getState dispatch location params'
]);
});

it('should get fetchDataDeferreds', () => {
const deps = getDataDependencies([
CompWithFetchData,
CompWithNoData,
CompWithFetchDataDeferred,
ConnectedCompWithFetchDataDeferred
], getState, dispatch, location, params, true);

expect(deps).to.deep.equal([
'fetchDataDeferred getState dispatch location params',
'fetchDataDeferred getState dispatch location params'
]);
});
});
14 changes: 8 additions & 6 deletions src/helpers/getDataDependencies.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
const getDataDependency = (component = {}) => {
const getDataDependency = (component = {}, methodName) => {
return component.WrappedComponent ?
getDataDependency(component.WrappedComponent) :
component.fetchData;
getDataDependency(component.WrappedComponent, methodName) :
component[methodName];
};

export default (components, getState, dispatch, location, params) => {
export default (components, getState, dispatch, location, params, deferred) => {
const methodName = deferred ? 'fetchDataDeferred' : 'fetchData';

return components
.filter((component) => getDataDependency(component)) // only look at ones with a static fetchData()
.map(getDataDependency) // pull out fetch data methods
.filter((component) => getDataDependency(component, methodName)) // only look at ones with a static fetchData()
.map((component) => getDataDependency(component, methodName)) // pull out fetch data methods
.map(fetchData =>
fetchData(getState, dispatch, location, params)); // call fetch data methods and save promises
};
16 changes: 11 additions & 5 deletions src/redux/middleware/transitionMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ export default ({getState, dispatch}) => next => action => {
next(action);
} else {
const {components, location, params} = action.payload;
const promises = getDataDependencies(components, getState, dispatch, location, params);
const promise = Promise.all(promises)
.then(
() => next(action)
);
const promise = new Promise((resolve) => {

const doTransition = () => {
next(action);
Promise.all(getDataDependencies(components, getState, dispatch, location, params, true))
.then(resolve, resolve);
};

Promise.all(getDataDependencies(components, getState, dispatch, location, params))
.then(doTransition, doTransition);
});

if (__SERVER__) {
// router state is null until ReduxRouter is created so we can use this to store
Expand Down

0 comments on commit c292c29

Please sign in to comment.