data-provider-temporary
Version:
Library that helps with server-to-client synchronization of data
280 lines (227 loc) • 10.9 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; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
exports.withRefetch = withRefetch;
exports.withDataProviders = withDataProviders;
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _DataProvider = require('./DataProvider');
var _DataProvider2 = _interopRequireDefault(_DataProvider);
var _util = require('./util');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function call(list) {
var fn = list[0];
var args = list.slice(1);
return fn.apply(undefined, _toConsumableArray(args));
}
var idg = new _util.IdGenerator();
var dataProviders = {};
function fetch(dpRef) {
var found = null;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _lodash2.default.values(dataProviders)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var dp = _step.value;
if (dp.ref === dpRef) {
if (found != null) {
throw new Error('Multiple data providers with the same ref=' + dpRef);
}
found = dp;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
if (found == null) {
throw new Error('No data provider ref=' + dpRef);
}
return found.fetch();
}
function withRefetch() {
return function (Component) {
return function (_React$Component) {
_inherits(ComponentWithRefetch, _React$Component);
function ComponentWithRefetch() {
_classCallCheck(this, ComponentWithRefetch);
return _possibleConstructorReturn(this, (ComponentWithRefetch.__proto__ || Object.getPrototypeOf(ComponentWithRefetch)).apply(this, arguments));
}
_createClass(ComponentWithRefetch, [{
key: 'render',
value: function render() {
var _this2 = this;
return _react2.default.createElement(Component, _extends({
refetch: function refetch(dpRef) {
// Make sure context is updated (shouldComponentUpdate of some
// parent component might prevent it from being updated)
_this2.forceUpdate();
fetch(dpRef);
}
}, this.props));
}
}]);
return ComponentWithRefetch;
}(_react2.default.Component);
};
}
function withDataProviders(getConfig) {
return function (Component) {
var _class, _temp;
return _temp = _class = function (_React$Component2) {
_inherits(ComponentWithDataProviders, _React$Component2);
function ComponentWithDataProviders() {
_classCallCheck(this, ComponentWithDataProviders);
return _possibleConstructorReturn(this, (ComponentWithDataProviders.__proto__ || Object.getPrototypeOf(ComponentWithDataProviders)).apply(this, arguments));
}
_createClass(ComponentWithDataProviders, [{
key: 'getChildContext',
value: function getChildContext() {
return { dataProviders: _extends({}, this.context.dataProviders, this.dataProviders) };
}
}, {
key: 'componentWillMount',
value: function componentWillMount() {
this.id = idg.next();
this.dataProviders = {};
this.handleUpdate(this.props);
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
// Make sure context is updated (shouldComponentUpdate of some parent
// component might prevent it from being updated)
this.forceUpdate();
this.handleUpdate(nextProps);
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
for (var dpId in this.dataProviders) {
dataProviders[dpId].removeUser(this.id);
}
}
}, {
key: 'handleUpdate',
value: function handleUpdate(props) {
var _this4 = this;
var newDataProviders = {};
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
var _loop = function _loop() {
var dpConfig = _step2.value;
var ref = dpConfig.ref,
rawGetData = dpConfig.getData,
rawOnData = dpConfig.onData,
initialData = dpConfig.initialData,
polling = dpConfig.polling,
needed = dpConfig.needed;
// Look for data provider with this ref among data providers of this
// component and data providers of its DOM ancestors
var dpId = _lodash2.default.findKey(_extends({}, _this4.context.dataProviders, _this4.dataProviders), function (dpRef) {
return _lodash2.default.isEqual(dpRef, ref);
});
var dp = void 0;
if (dpId == null) {
(0, _util.assert)(rawOnData != null && rawGetData != null, 'Parameters onData, getData have to be provided, if data' + ('provider was not defined yet. See DP ' + ref));
dpId = idg.next();
dataProviders[dpId] = new _DataProvider2.default({
id: dpId,
ref: ref,
rawOnData: rawOnData,
onData: function onData(data) {
call(rawOnData)(ref, data, _this4.context.dispatch);
_this4.forceUpdate();
},
initialData: initialData
});
}
dp = dataProviders[dpId];
// Changing onData for existing data provider is not currently
// supported
(0, _util.assert)(rawOnData == null || _lodash2.default.isEqual(rawOnData, dp.rawOnData), 'Provided onData for DP ' + ref + '\n' + rawOnData + '\n' + ('is not equal to previous onData\n' + dp.rawOnData));
// If the data provider was already defined in some DOM ancestor,
// require equality on getData (i.e. there can be only one definition
// of getData for any tuple of (ref, moment in time, DOM node))
if (_lodash2.default.has(_this4.context.dataProviders, dpId)) {
(0, _util.assert)(rawGetData == null || _lodash2.default.isEqual(rawGetData, dp.rawGetData), 'Provided getData for DP ' + ref + '\n' + rawGetData + '\n' + ('is not equal to previous getData\n' + dp.rawGetData));
}
dp.updateUser(_this4.id, {
polling: polling,
needed: needed,
rawGetData: rawGetData,
getData: function getData() {
return call(rawGetData);
}
});
newDataProviders[dpId] = dp.ref;
};
for (var _iterator2 = getConfig(props)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
_loop();
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
for (var dpId in this.dataProviders) {
if (!_lodash2.default.has(newDataProviders, dpId)) {
dataProviders[dpId].removeUser(this.id);
}
}
this.dataProviders = newDataProviders;
this.forceUpdate();
}
}, {
key: 'render',
value: function render() {
var _this5 = this;
var show = _lodash2.default.keys(this.dataProviders).every(function (id) {
var dp = dataProviders[id];
return !dp.userConfigs[_this5.id].needed || dp.loaded;
});
return show ? _react2.default.createElement(Component, this.props) : null;
}
}]);
return ComponentWithDataProviders;
}(_react2.default.Component), _class.contextTypes = {
dispatch: _propTypes2.default.func.isRequired,
dataProviders: _propTypes2.default.object
}, _class.childContextTypes = {
dataProviders: _propTypes2.default.object
}, _temp;
};
}