Skip to content

Commit

Permalink
Merge pull request #19 from kouhin/release/v0.5.0
Browse files Browse the repository at this point in the history
Release/v0.5.0
  • Loading branch information
kouhin authored Mar 9, 2017
2 parents e0ed8e6 + c97ce91 commit cc9df98
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 120 deletions.
11 changes: 9 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
{
"presets": ["es2015", "react", "stage-0"]
}
"presets": [
"env",
"react",
"stage-0"
],
"plugins": [
"transform-runtime"
]
}
19 changes: 10 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-router-hook",
"version": "0.4.1",
"version": "0.5.0",
"description": "Universal data fetching and lifecycle management for react router with multiple components",
"main": "./lib/index.js",
"scripts": {
Expand Down Expand Up @@ -32,20 +32,21 @@
],
"license": "MIT",
"devDependencies": {
"babel-cli": "^6.22.2",
"babel-core": "^6.22.1",
"babel-cli": "^6.23.0",
"babel-core": "^6.23.1",
"babel-eslint": "^7.1.1",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.22.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.2.1",
"babel-preset-react": "^6.23.0",
"babel-preset-stage-0": "^6.22.0",
"eslint-config-airbnb-deps": "^14.0.0",
"eslint-plugin-babel": "^4.0.1",
"eslint-config-airbnb-deps": "^14.1.0",
"eslint-plugin-babel": "^4.1.1",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"rimraf": "^2.5.4"
"rimraf": "^2.6.1"
},
"dependencies": {
"async": "^2.1.4",
"babel-runtime": "^6.23.0",
"eventemitter3": "^2.0.2",
"lodash": "^4.17.4",
"uuid": "^3.0.1"
Expand Down
190 changes: 83 additions & 107 deletions src/RouterHookContainer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import React from 'react';
import series from 'async/series';
import asyncify from 'async/asyncify';
import mapSeries from 'async/mapSeries';

import { ComponentStatus, routerHookPropName } from './constants';
import getInitStatus from './getInitStatus';
Expand All @@ -26,54 +23,48 @@ export default class RouterHookContainer extends React.Component {
super(props, context);
this.setStatus = this.setStatus.bind(this);
this.reloadComponent = this.reloadComponent.bind(this);
this.mounted = false;

this.shouldReload = false;
this.mounted = false;
this.state = {
status: getInitStatus(
props.children.type,
this.props.routerWillEnterHooks,
),
childProps: {},
};
}

componentWillMount() {
this.context.routerHookContext.setComponentStatus(this.Component, this.state.status);
this.context.routerHookContext.setComponentStatus(this.Component, getInitStatus(
this.Component,
this.props.routerWillEnterHooks,
));
}

componentDidMount() {
this.mounted = true;
setTimeout(() => {
setImmediate(() => {
this.reloadComponent(true);
});
}

componentWillReceiveProps(nextProps) {
if (this.props.renderProps.location !== nextProps.renderProps.location) {
this.context.routerHookContext.setComponentStatus(this.Component, getInitStatus(
this.Component,
this.props.routerWillEnterHooks,
));
this.setState({
status: getInitStatus(
this.Component,
this.props.routerWillEnterHooks,
),
childProps: {},
});
this.shouldReload = true;
if (this.mounted) {
this.forceUpdate();
}
return;
}

if (this.mounted) {
this.forceUpdate();
}
}

componentDidUpdate() {
if (this.shouldReload) {
this.shouldReload = false;
setTimeout(() => {
componentDidUpdate(prevProps) {
if (this.props.renderProps.location !== prevProps.renderProps.location) {
setImmediate(() => {
this.reloadComponent(true);
});
}
Expand All @@ -84,28 +75,36 @@ export default class RouterHookContainer extends React.Component {
}

setStatus(status, shouldReport, err) {
const shouldUpdate = this.state.status !== status;
this.setState({
status,
});
if (shouldReport) {
this.context.routerHookContext.setComponentStatus(this.Component, status, err);
if (this.state.status === status) {
return Promise.resolve();
}
if (shouldUpdate) {
if (this.mounted) {
this.forceUpdate();
return new Promise((resolve) => {
if (!this.mounted) {
resolve();
return;
}
}
this.setState({
status,
}, () => {
if (shouldReport) {
this.context.routerHookContext.setComponentStatus(this.Component, status, err);
}
resolve();
});
});
}

get Component() {
return this.props.children.type;
}

reloadComponent(shouldReportStatus = false) {
if (!this.mounted) {
return Promise.resolve();
}
const routerHooks = this.Component[routerHookPropName];
if (!routerHooks) {
return;
return Promise.resolve();
}
/* eslint-disable no-unused-vars */
const {
Expand All @@ -122,97 +121,75 @@ export default class RouterHookContainer extends React.Component {
routerWillEnterHooks,
);

this.setStatus(initStatus, shouldReportStatus);
if (initStatus === ComponentStatus.DONE) {
return;
}

const location = renderProps.location;

const args = {
...renderProps,
...locals,
getProps: () => this.state.childProps,
setProps: (p) => {
if (location === renderProps.location) {
this.setState({
childProps: {
...this.state.childProps,
...p,
},
});
if (this.mounted) {
this.forceUpdate();
}
}
},
};

series([
(callback) => {
if (location !== renderProps.location) {
callback(ABORT);
return;
return this.setStatus(initStatus, shouldReportStatus)
.then(() => {
if (location !== renderProps.location || !this.mounted) {
return Promise.reject(ABORT);
}
if (initStatus === 'init') {
callback();
return;
if (this.state.status !== ComponentStatus.INIT) {
return null;
}
const willEnterHooks = routerWillEnterHooks
.map(key => routerHooks[key])
.filter(f => f)
.map(f => asyncify(f));
if (willEnterHooks.length > 0) {
mapSeries(willEnterHooks, (hook, cb) => {
if (location === renderProps.location) {
hook(args, cb);
.map(key => routerHooks[key])
.filter(f => f);
if (willEnterHooks.length < 1) {
return null;
}
return willEnterHooks
.reduce((total, hook) => total.then(() => {
if (location !== renderProps.location || !this.mounted) {
return Promise.reject(ABORT);
}
}, callback);
} else {
callback();
return hook(args);
}), Promise.resolve());
})
.then(() => {
if (location !== renderProps.location || !this.mounted) {
return Promise.reject(ABORT);
}
},
(callback) => {
if (location !== renderProps.location) {
callback(ABORT);
return;
if (this.state.status !== ComponentStatus.INIT) {
return null;
}
this.setStatus(ComponentStatus.DEFER, shouldReportStatus);
callback();
},
(callback) => {
if (location !== renderProps.location) {
callback(ABORT);
return;
// Wait for rendering
return this.setStatus(ComponentStatus.DEFER, shouldReportStatus);
})
.then(() => {
if (location !== renderProps.location || !this.mounted) {
return Promise.reject(ABORT);
}
const didEnterHooks = routerDidEnterHooks
.map(key => routerHooks[key])
.filter(f => f)
.map(f => asyncify(f));
if (didEnterHooks.length > 0) {
mapSeries(didEnterHooks, (hook, cb) => {
if (location === renderProps.location) {
hook(args, cb);
.map(key => routerHooks[key])
.filter(f => f);
if (didEnterHooks.length < 1) {
return null;
}
return didEnterHooks
.reduce((total, hook) => total.then(() => {
if (location !== renderProps.location || !this.mounted) {
return Promise.reject(ABORT);
}
}, callback);
} else {
callback();
return hook(args);
}), Promise.resolve());
})
.then(() => {
if (location !== renderProps.location || !this.mounted) {
return Promise.reject(ABORT);
}
},
(callback) => {
if (location !== renderProps.location) {
callback(ABORT);
return;
return this.setStatus(ComponentStatus.DONE, shouldReportStatus);
})
.catch((err) => {
if (err === ABORT) {
return null;
}
this.setStatus(ComponentStatus.DONE, shouldReportStatus);
callback();
},
], (err) => {
if (err && err === ABORT) {
return;
}
this.setStatus(ComponentStatus.DONE, shouldReportStatus, err);
});
return this.setStatus(ComponentStatus.DONE, shouldReportStatus, err);
});
}

render() {
Expand All @@ -228,7 +205,6 @@ export default class RouterHookContainer extends React.Component {
/* eslint-enable no-unused-vars */
const passProps = {
...restProps,
...this.state.childProps,
componentStatus: this.state.status,
reloadComponent: this.reloadComponent,
};
Expand Down
5 changes: 3 additions & 2 deletions src/RouterHookContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default class RouterHookContext extends React.Component {
if (nextProps.location === this.props.location) {
return;
}
this.componentStatuses = {};
if (this.loading) {
this.props.onAborted();
}
Expand All @@ -73,11 +74,11 @@ export default class RouterHookContext extends React.Component {
return;
}
this.componentStatuses[routerHooks.id] = status;
this.updateRouterLoading();
if (err) {
this.props.onError({ Component, error: err });
this.componentStatuses[routerHooks.id] = ComponentStatus.DONE;
}
this.updateRouterLoading();
}

getComponentStatus(Component) {
Expand Down Expand Up @@ -129,7 +130,7 @@ export default class RouterHookContext extends React.Component {
}
}

const loading = done !== total;
const loading = done < total;
if (this.routerEventEmitter) {
this.routerEventEmitter.emit(CHANGE_LOADING_STATE, loading, {
total,
Expand Down

0 comments on commit cc9df98

Please sign in to comment.