UNPKG

gambit

Version:

A hyper-thin library to help building API driven redux apps

244 lines (182 loc) 7.81 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _defineProperty2 = require('babel-runtime/helpers/defineProperty'); var _defineProperty3 = _interopRequireDefault(_defineProperty2); var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray'); var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); var _keys = require('babel-runtime/core-js/object/keys'); var _keys2 = _interopRequireDefault(_keys); var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); exports.default = containerFactory; var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _forIn = require('lodash/forIn'); var _forIn2 = _interopRequireDefault(_forIn); var _bluebird = require('bluebird'); var _bluebird2 = _interopRequireDefault(_bluebird); var _invariant = require('invariant'); var _invariant2 = _interopRequireDefault(_invariant); var _containerHelpers = require('./containerHelpers'); var _dict = require('./dict'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } if (typeof document !== 'undefined') { require('./reactErrorPatch.js'); } function containerFactory(ComponentToWrap, _ref) { var fetch = _ref.fetch; var methods = _ref.methods; var done = _ref.done; var pending = _ref.pending; var failed = _ref.failed; var propTransform = _ref.propTransform; var strictMode = _ref.strictMode; var logging = _ref.logging; (0, _invariant2.default)(ComponentToWrap, (0, _dict.badComponent)(fetch)); var name = ComponentToWrap.displayName; var WrappedComponent = (0, _containerHelpers.connectComponent)(ComponentToWrap, fetch, methods, name); var Gambit = function (_React$Component) { (0, _inherits3.default)(Gambit, _React$Component); function Gambit(props, context) { (0, _classCallCheck3.default)(this, Gambit); var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(Gambit).call(this, props, context)); _this.state = { loadingFetches: 0, errored: false, handlingRefreshGrab: [] }; return _this; } (0, _createClass3.default)(Gambit, [{ key: 'runFetches', value: function runFetches(props, fetchesToRun) { var _this2 = this; var cb = arguments.length <= 2 || arguments[2] === undefined ? function () {} : arguments[2]; if (propTransform) { props = propTransform(props); } var promiseObj = {}; var store = this.context.store.getState(); (0, _forIn2.default)(fetchesToRun, function (value, key) { if (value.grab) { var grab = void 0, as = void 0; try { grab = value.grab(props.dispatch, props); as = value.as(store, props); } catch (e) { console.warn('Error in ' + name, e); } (0, _invariant2.default)(typeof grab === 'function', (0, _dict.badGrab)(name, key, grab)); promiseObj[key] = grab(as); } }); var allCallsBlocked = (0, _keys2.default)(promiseObj).every(function (x) { return !promiseObj[x]; }); if (allCallsBlocked) { return false; } this.setState({ loadingFetches: this.state.loadingFetches + 1 }); return _bluebird2.default.props(promiseObj).then(function (object) { (0, _keys2.default)(object).forEach(function (key) { (0, _invariant2.default)(object[key] !== undefined, (0, _dict.badGrabReturn)(name, key, object[key])); }); _this2.setState({ loadingFetches: _this2.state.loadingFetches - 1, errored: false }, cb); // Workaround for https://github.com/petkaantonov/bluebird/issues/846 return null; }).catch(function (err) { _this2.setState({ loadingFetches: _this2.state.loadingFetches - 1, errored: err }, cb); }); } }, { key: 'componentWillMount', value: function componentWillMount() { var _this3 = this; var store = this.context.store; this.runFetches(this.props, fetch); // We have refreshGrabInResponse // because when a component has a small view into a larger data set (i.e. between some dates) // it's generally the only part of the application that knows what view it has and so // it's best place to re-run the grab function that provides its data. store.subscribe(function () { var state = store.getState(); (0, _forIn2.default)(fetch, function (value, key) { var refreshGrabInResponse = value.refreshGrabInResponse; if (!refreshGrabInResponse) return null; if (typeof refreshGrabInResponse === 'function') { var parseProps = propTransform ? propTransform(_this3.props) : _this3.props; refreshGrabInResponse = refreshGrabInResponse(state, parseProps); } if (refreshGrabInResponse.indexOf(state.gambit.get('lastAction')) !== -1 && _this3.state.handlingRefreshGrab.indexOf(key) === -1) { return _this3.setState({ handlingRefreshGrab: [].concat((0, _toConsumableArray3.default)(_this3.state.handlingRefreshGrab), [key]) }, function () { return _this3.runFetches(_this3.props, (0, _defineProperty3.default)({}, key, value), function () { _this3.setState({ handlingRefreshGrab: _this3.state.handlingRefreshGrab.filter(function (x) { return x !== key; }) }); }); }); } return null; }); }); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { this.runFetches(nextProps, fetch); } }, { key: 'render', value: function render() { var _state = this.state; var loadingFetches = _state.loadingFetches; var errored = _state.errored; var parseProps = propTransform ? propTransform(this.props) : this.props; if (loadingFetches !== 0 && pending) { return pending.call(this, WrappedComponent); } else if (loadingFetches === 0 && !errored) { if (done) { return done.call(this, WrappedComponent); } return _react2.default.createElement(WrappedComponent, parseProps); } else if (loadingFetches === 0 && errored) { if (failed) { console.warn('Failed in ' + name + ': ' + errored); return failed.call(this, WrappedComponent); } throw new Error(errored); } return null; } }]); return Gambit; }(_react2.default.Component); Gambit.contextTypes = { store: _react2.default.PropTypes.object }; Gambit.displayName = 'Container(' + name + ')'; return Gambit; }