react-router
Version:
A complete routing library for React.js
131 lines (105 loc) • 4.23 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
function shallowEqual(a, b) {
var ka = 0;
var kb = 0;
for (var key in a) {
if (a.hasOwnProperty(key) && a[key] !== b[key]) return false;
ka++;
}
for (var key in b) {
if (b.hasOwnProperty(key)) kb++;
}return ka === kb;
}
var AsyncProps = _react2['default'].createClass({
displayName: 'AsyncProps',
statics: {
createElement: function createElement(Component, state) {
return Component.loadProps ? _react2['default'].createElement(AsyncProps, { Component: Component, routing: state }) : _react2['default'].createElement(Component, state);
}
},
getInitialState: function getInitialState() {
return {
propsAreLoading: false,
propsAreLoadingLong: false,
asyncProps: null,
previousRoutingState: null
};
},
componentDidMount: function componentDidMount() {
this.load(this.props);
},
componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
var _this = this;
var needToLoad = !shallowEqual(nextProps.routing.routeParams, this.props.routing.routeParams);
if (needToLoad) {
var routerTransitioned = nextProps.routing.location !== this.props.routing.location;
var keepPreviousRoutingState = this.state.propsAreLoadingLong && routerTransitioned;
if (keepPreviousRoutingState) {
this.load(nextProps);
} else {
this.setState({
previousRoutingState: this.props.routing
}, function () {
return _this.load(nextProps);
});
}
}
},
/*
* Could make this method much better, right now AsyncProps doesn't render its
* children until it fetches data, causing a "waterfall" effect, when instead
* it could look at the branch of components from it down to the end and load
* up the props for all of them in parallel, waterfall will do for now...
*/
load: function load(props) {
var _this2 = this;
var lastLoadTime = this._lastLoadTime = Date.now();
var params = props.routing.params;
var Component = this.props.Component;
this.setState({ propsAreLoading: true }, function () {
var longLoadTimer = setTimeout(function () {
_this2.setState({ propsAreLoadingLong: true });
}, 300);
// TODO: handle `error`s
Component.loadProps(params, function (error, asyncProps) {
clearTimeout(longLoadTimer);
// if the router transitions between now and when the callback runs we will
// ignore it to prevent setting state w/ the wrong data (earlier calls to
// load that call back later than later calls to load)
if (_this2._lastLoadTime !== lastLoadTime || !_this2.isMounted()) return;
_this2.setState({
propsAreLoading: false,
propsAreLoadingLong: false,
asyncProps: asyncProps,
previousRoutingState: null
});
});
});
},
render: function render() {
var _this3 = this;
var Component = this.props.Component;
var _state = this.state;
var asyncProps = _state.asyncProps;
var propsAreLoading = _state.propsAreLoading;
var propsAreLoadingLong = _state.propsAreLoadingLong;
var routing = this.state.previousRoutingState || this.props.routing;
if (this.state.asyncProps === null) return Component.Loader ? _react2['default'].createElement(Component.Loader, routing) : null;
return _react2['default'].createElement(Component, _extends({
onPropsDidChange: function () {
return _this3.load(_this3.props);
},
propsAreLoading: propsAreLoading,
propsAreLoadingLong: propsAreLoadingLong
}, routing, asyncProps));
}
});
exports['default'] = AsyncProps;
module.exports = exports['default'];