UNPKG

data-provider-temporary

Version:

Library that helps with server-to-client synchronization of data

185 lines (148 loc) 5.89 kB
'use strict'; 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; }; 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 call(list) { let fn = list[0]; let args = list.slice(1); return fn(...args); } const idg = new _util.IdGenerator(); const dataProviders = {}; function fetch(dpRef) { let found = null; for (let dp of _lodash2.default.values(dataProviders)) { if (dp.ref === dpRef) { if (found != null) { throw new Error(`Multiple data providers with the same ref=${dpRef}`); } found = dp; } } if (found == null) { throw new Error(`No data provider ref=${dpRef}`); } return found.fetch(); } function withRefetch() { return Component => { return class ComponentWithRefetch extends _react2.default.Component { render() { return _react2.default.createElement(Component, _extends({ refetch: dpRef => { // Make sure context is updated (shouldComponentUpdate of some // parent component might prevent it from being updated) this.forceUpdate(); fetch(dpRef); } }, this.props)); } }; }; } function withDataProviders(getConfig) { return Component => { var _class, _temp; return _temp = _class = class ComponentWithDataProviders extends _react2.default.Component { getChildContext() { return { dataProviders: _extends({}, this.context.dataProviders, this.dataProviders) }; } componentWillMount() { this.id = idg.next(); this.dataProviders = {}; this.handleUpdate(this.props); } componentWillReceiveProps(nextProps) { // Make sure context is updated (shouldComponentUpdate of some parent // component might prevent it from being updated) this.forceUpdate(); this.handleUpdate(nextProps); } componentWillUnmount() { for (let dpId in this.dataProviders) { dataProviders[dpId].removeUser(this.id); } } handleUpdate(props) { let newDataProviders = {}; for (let dpConfig of getConfig(props)) { let { ref, getData: rawGetData, onData: rawOnData, initialData, polling, needed } = dpConfig; // Look for data provider with this ref among data providers of this // component and data providers of its DOM ancestors let dpId = _lodash2.default.findKey(_extends({}, this.context.dataProviders, this.dataProviders), dpRef => _lodash2.default.isEqual(dpRef, ref)); let dp; 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, rawOnData, onData: data => { call(rawOnData)(ref, data, this.context.dispatch); this.forceUpdate(); }, 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(this.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(this.id, { polling, needed, rawGetData, getData: () => call(rawGetData) }); newDataProviders[dpId] = dp.ref; } for (let dpId in this.dataProviders) { if (!_lodash2.default.has(newDataProviders, dpId)) { dataProviders[dpId].removeUser(this.id); } } this.dataProviders = newDataProviders; this.forceUpdate(); } render() { let show = _lodash2.default.keys(this.dataProviders).every(id => { let dp = dataProviders[id]; return !dp.userConfigs[this.id].needed || dp.loaded; }); return show ? _react2.default.createElement(Component, this.props) : null; } }, _class.contextTypes = { dispatch: _propTypes2.default.func.isRequired, dataProviders: _propTypes2.default.object }, _class.childContextTypes = { dataProviders: _propTypes2.default.object }, _temp; }; }