UNPKG

react-async-call

Version:
1,377 lines (1,160 loc) 50.3 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = require('react'); var React__default = _interopDefault(React); var PropTypes = require('prop-types'); var PropTypes__default = _interopDefault(PropTypes); /** * Copyright (c) 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ function makeEmptyFunction(arg) { return function () { return arg; }; } /** * This function accepts and discards inputs; it has no side effects. This is * primarily useful idiomatically for overridable function endpoints which * always need to be callable, since JS lacks a null-call idiom ala Cocoa. */ function emptyFunction() {} emptyFunction.thatReturns = makeEmptyFunction; emptyFunction.thatReturnsFalse = makeEmptyFunction(false); emptyFunction.thatReturnsTrue = makeEmptyFunction(true); emptyFunction.thatReturnsNull = makeEmptyFunction(null); emptyFunction.thatReturnsThis = function () { return this; }; emptyFunction.thatReturnsArgument = function (arg) { return arg; }; var emptyFunction_1 = emptyFunction; /** * Similar to invariant but only logs a warning if the condition is not met. * This can be used to log issues in development environments in critical * paths. Removing the logging code for production environments will keep the * same logic and follow the same code paths. */ var warning = emptyFunction_1; { warning = function (condition, format) { for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { args[_key - 2] = arguments[_key]; } if (format === undefined) { throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); } if (format.indexOf('Failed Composite propType: ') === 0) { return; // Ignore CompositeComponent proptype check. } if (!condition) { var argIndex = 0; var message = 'Warning: ' + format.replace(/%s/g, function () { return args[argIndex++]; }); if (typeof console !== 'undefined') { console.error(message); } try { // --- Welcome to debugging React --- // This error was thrown as a convenience so that you can use this stack // to find the callsite that caused this warning to fire. throw new Error(message); } catch (x) {} } }; } var warning_1 = warning; /** * Copyright (c) 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @typechecks * */ var hasOwnProperty = Object.prototype.hasOwnProperty; /** * inlined Object.is polyfill to avoid requiring consumers ship their own * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is */ function is(x, y) { // SameValue algorithm if (x === y) { // Steps 1-5, 7-10 // Steps 6.b-6.e: +0 != -0 return x !== 0 || 1 / x === 1 / y; } else { // Step 6.a: NaN == NaN return x !== x && y !== y; } } /** * Performs equality by iterating through keys on an object and returning false * when any key has values which are not strictly equal between the arguments. * Returns true when the values of all keys are strictly equal. */ function shallowEqual(objA, objB) { if (is(objA, objB)) { return true; } if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { return false; } var keysA = Object.keys(objA); var keysB = Object.keys(objB); if (keysA.length !== keysB.length) { return false; } // Test for A's keys different from B. for (var i = 0; i < keysA.length; i++) { if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { return false; } } return true; } var shallowEqual_1 = shallowEqual; var isFunction = function isFunction(value) { return !!(value && value.constructor && value.call && value.apply); }; var renderChildren = function renderChildren(props, arg) { return (isFunction(props.children) ? props.children(arg) : props.children) || null; }; var renderChildrenFn = function renderChildrenFn(props, arg) { return isFunction(props.children) && props.children(arg) || null; }; var createAsyncCallChild = function createAsyncCallChild(Consumer, rootDisplayName, renderFn, displayName, childrenPropType) { var Child = function Child(props) { return React.createElement( Consumer, null, function (contextProps) { invariant(contextProps, INVARIANT_MUST_BE_A_CHILD, Child.displayName, rootDisplayName); return renderFn(props, contextProps) || null; } ); }; { Child.propTypes = { children: childrenPropType }; Child.displayName = rootDisplayName + '.' + displayName; } return Child; }; var nodePropType = void 0; var requiredFuncPropType = void 0; var nodeOrFuncPropType = void 0; var INVARIANT_MUST_BE_A_CHILD = void 0; var INVARIANT_FUNCTION_SHOULD_BE_PASSED = void 0; var INVARIANT_FUNCTION_SHOULD_RETURN_PROMISE = void 0; var WARNING_PROPERTY_RESET_IS_DEPRECATED = void 0; var DISPLAY_NAME_COMPLETED = void 0; var DISPLAY_NAME_EXECUTOR = void 0; var DISPLAY_NAME_REJECTED = void 0; var DISPLAY_NAME_RESOLVED = void 0; var DISPLAY_NAME_RUNNING = void 0; var DISPLAY_NAME_STATE = void 0; var DISPLAY_NAME_RESETTER = void 0; var DISPLAY_NAME_HAS_RESULT = void 0; { nodePropType = PropTypes.node; requiredFuncPropType = PropTypes.func.isRequired; nodeOrFuncPropType = PropTypes.oneOfType([PropTypes.node, PropTypes.func]); INVARIANT_MUST_BE_A_CHILD = '<%s> must be a child (direct or indirect) of <%s>.'; INVARIANT_FUNCTION_SHOULD_BE_PASSED = 'Function should be passed to createAsyncCallComponent as a first argument but got %s.'; INVARIANT_FUNCTION_SHOULD_RETURN_PROMISE = 'Function supplied to "createAsyncCallComponent" function should return a promise.'; WARNING_PROPERTY_RESET_IS_DEPRECATED = 'Property `reset` of <AsyncCall.ResultStore> component is deprecated. Use <AsyncCall.ResultStore.Resetter> component instead.'; DISPLAY_NAME_COMPLETED = 'Completed'; DISPLAY_NAME_EXECUTOR = 'Executor'; DISPLAY_NAME_REJECTED = 'Rejected'; DISPLAY_NAME_RESOLVED = 'Resolved'; DISPLAY_NAME_RUNNING = 'Running'; DISPLAY_NAME_STATE = 'State'; DISPLAY_NAME_RESETTER = 'Resetter'; DISPLAY_NAME_HAS_RESULT = 'HasResult'; } /** * Use invariant() to assert state which your program assumes to be true. * * Provide sprintf-style format (only %s is supported) and arguments * to provide information about what broke and what you were * expecting. * * The invariant message will be stripped in production, but the invariant * will remain to ensure logic does not differ in production. */ function invariant(condition, format, a, b, c, d, e, f) { if (!condition) { var error; { if (format === undefined) { throw new Error('invariant requires an error message argument'); } var args = [a, b, c, d, e, f]; var argIndex = 0; error = new Error(format.replace(/%s/g, function () { return args[argIndex++]; })); error.name = 'Invariant Violation'; } error.framesToPop = 1; // we don't care about invariant's own frame throw error; } } var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function unwrapExports (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var key = '__global_unique_id__'; var gud = function() { return commonjsGlobal[key] = (commonjsGlobal[key] || 0) + 1; }; var implementation = createCommonjsModule(function (module, exports) { exports.__esModule = true; var _react2 = _interopRequireDefault(React__default); var _propTypes2 = _interopRequireDefault(PropTypes__default); var _gud2 = _interopRequireDefault(gud); var _warning2 = _interopRequireDefault(warning_1); 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; } var MAX_SIGNED_31_BIT_INT = 1073741823; // Inlined Object.is polyfill. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is function objectIs(x, y) { if (x === y) { return x !== 0 || 1 / x === 1 / y; } else { return x !== x && y !== y; } } function createEventEmitter(value) { var handlers = []; return { on: function on(handler) { handlers.push(handler); }, off: function off(handler) { handlers = handlers.filter(function (h) { return h !== handler; }); }, get: function get() { return value; }, set: function set(newValue, changedBits) { value = newValue; handlers.forEach(function (handler) { return handler(value, changedBits); }); } }; } function onlyChild(children) { return Array.isArray(children) ? children[0] : children; } function createReactContext(defaultValue, calculateChangedBits) { var _Provider$childContex, _Consumer$contextType; var contextProp = '__create-react-context-' + (0, _gud2.default)() + '__'; var Provider = function (_Component) { _inherits(Provider, _Component); function Provider() { var _temp, _this, _ret; _classCallCheck(this, Provider); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _this.emitter = createEventEmitter(_this.props.value), _temp), _possibleConstructorReturn(_this, _ret); } Provider.prototype.getChildContext = function getChildContext() { var _ref; return _ref = {}, _ref[contextProp] = this.emitter, _ref; }; Provider.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { if (this.props.value !== nextProps.value) { var oldValue = this.props.value; var newValue = nextProps.value; var changedBits = void 0; if (objectIs(oldValue, newValue)) { changedBits = 0; // No change } else { changedBits = typeof calculateChangedBits === 'function' ? calculateChangedBits(oldValue, newValue) : MAX_SIGNED_31_BIT_INT; { (0, _warning2.default)((changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, 'calculateChangedBits: Expected the return value to be a ' + '31-bit integer. Instead received: %s', changedBits); } changedBits |= 0; if (changedBits !== 0) { this.emitter.set(nextProps.value, changedBits); } } } }; Provider.prototype.render = function render() { return this.props.children; }; return Provider; }(React__default.Component); Provider.childContextTypes = (_Provider$childContex = {}, _Provider$childContex[contextProp] = _propTypes2.default.object.isRequired, _Provider$childContex); var Consumer = function (_Component2) { _inherits(Consumer, _Component2); function Consumer() { var _temp2, _this2, _ret2; _classCallCheck(this, Consumer); for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return _ret2 = (_temp2 = (_this2 = _possibleConstructorReturn(this, _Component2.call.apply(_Component2, [this].concat(args))), _this2), _this2.state = { value: _this2.getValue() }, _this2.onUpdate = function (newValue, changedBits) { var observedBits = _this2.observedBits | 0; if ((observedBits & changedBits) !== 0) { _this2.setState({ value: _this2.getValue() }); } }, _temp2), _possibleConstructorReturn(_this2, _ret2); } Consumer.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) { var observedBits = nextProps.observedBits; this.observedBits = observedBits === undefined || observedBits === null ? MAX_SIGNED_31_BIT_INT // Subscribe to all changes by default : observedBits; }; Consumer.prototype.componentDidMount = function componentDidMount() { if (this.context[contextProp]) { this.context[contextProp].on(this.onUpdate); } var observedBits = this.props.observedBits; this.observedBits = observedBits === undefined || observedBits === null ? MAX_SIGNED_31_BIT_INT // Subscribe to all changes by default : observedBits; }; Consumer.prototype.componentWillUnmount = function componentWillUnmount() { if (this.context[contextProp]) { this.context[contextProp].off(this.onUpdate); } }; Consumer.prototype.getValue = function getValue() { if (this.context[contextProp]) { return this.context[contextProp].get(); } else { return defaultValue; } }; Consumer.prototype.render = function render() { return onlyChild(this.props.children)(this.state.value); }; return Consumer; }(React__default.Component); Consumer.contextTypes = (_Consumer$contextType = {}, _Consumer$contextType[contextProp] = _propTypes2.default.object, _Consumer$contextType); return { Provider: Provider, Consumer: Consumer }; } exports.default = createReactContext; module.exports = exports['default']; }); unwrapExports(implementation); var lib = createCommonjsModule(function (module, exports) { exports.__esModule = true; var _react2 = _interopRequireDefault(React__default); var _implementation2 = _interopRequireDefault(implementation); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } exports.default = _react2.default.createContext || _implementation2.default; module.exports = exports['default']; }); var createContext = unwrapExports(lib); /** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ function componentWillMount() { // Call this.constructor.gDSFP to support sub-classes. var state = this.constructor.getDerivedStateFromProps(this.props, this.state); if (state !== null && state !== undefined) { this.setState(state); } } function componentWillReceiveProps(nextProps) { // Call this.constructor.gDSFP to support sub-classes. // Use the setState() updater to ensure state isn't stale in certain edge cases. function updater(prevState) { var state = this.constructor.getDerivedStateFromProps(nextProps, prevState); return state !== null && state !== undefined ? state : null; } // Binding "this" is important for shallow renderer support. this.setState(updater.bind(this)); } function componentWillUpdate(nextProps, nextState) { try { var prevProps = this.props; var prevState = this.state; this.props = nextProps; this.state = nextState; this.__reactInternalSnapshotFlag = true; this.__reactInternalSnapshot = this.getSnapshotBeforeUpdate( prevProps, prevState ); } finally { this.props = prevProps; this.state = prevState; } } // React may warn about cWM/cWRP/cWU methods being deprecated. // Add a flag to suppress these warnings for this special case. componentWillMount.__suppressDeprecationWarning = true; componentWillReceiveProps.__suppressDeprecationWarning = true; componentWillUpdate.__suppressDeprecationWarning = true; function polyfill(Component) { var prototype = Component.prototype; if (!prototype || !prototype.isReactComponent) { throw new Error('Can only polyfill class components'); } if ( typeof Component.getDerivedStateFromProps !== 'function' && typeof prototype.getSnapshotBeforeUpdate !== 'function' ) { return Component; } // If new component APIs are defined, "unsafe" lifecycles won't be called. // Error if any of these lifecycles are present, // Because they would work differently between older and newer (16.3+) versions of React. var foundWillMountName = null; var foundWillReceivePropsName = null; var foundWillUpdateName = null; if (typeof prototype.componentWillMount === 'function') { foundWillMountName = 'componentWillMount'; } else if (typeof prototype.UNSAFE_componentWillMount === 'function') { foundWillMountName = 'UNSAFE_componentWillMount'; } if (typeof prototype.componentWillReceiveProps === 'function') { foundWillReceivePropsName = 'componentWillReceiveProps'; } else if (typeof prototype.UNSAFE_componentWillReceiveProps === 'function') { foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps'; } if (typeof prototype.componentWillUpdate === 'function') { foundWillUpdateName = 'componentWillUpdate'; } else if (typeof prototype.UNSAFE_componentWillUpdate === 'function') { foundWillUpdateName = 'UNSAFE_componentWillUpdate'; } if ( foundWillMountName !== null || foundWillReceivePropsName !== null || foundWillUpdateName !== null ) { var componentName = Component.displayName || Component.name; var newApiName = typeof Component.getDerivedStateFromProps === 'function' ? 'getDerivedStateFromProps()' : 'getSnapshotBeforeUpdate()'; throw Error( 'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' + componentName + ' uses ' + newApiName + ' but also contains the following legacy lifecycles:' + (foundWillMountName !== null ? '\n ' + foundWillMountName : '') + (foundWillReceivePropsName !== null ? '\n ' + foundWillReceivePropsName : '') + (foundWillUpdateName !== null ? '\n ' + foundWillUpdateName : '') + '\n\nThe above lifecycles should be removed. Learn more about this warning here:\n' + 'https://fb.me/react-async-component-lifecycle-hooks' ); } // React <= 16.2 does not support static getDerivedStateFromProps. // As a workaround, use cWM and cWRP to invoke the new static lifecycle. // Newer versions of React will ignore these lifecycles if gDSFP exists. if (typeof Component.getDerivedStateFromProps === 'function') { prototype.componentWillMount = componentWillMount; prototype.componentWillReceiveProps = componentWillReceiveProps; } // React <= 16.2 does not support getSnapshotBeforeUpdate. // As a workaround, use cWU to invoke the new lifecycle. // Newer versions of React will ignore that lifecycle if gSBU exists. if (typeof prototype.getSnapshotBeforeUpdate === 'function') { if (typeof prototype.componentDidUpdate !== 'function') { throw new Error( 'Cannot polyfill getSnapshotBeforeUpdate() for components that do not define componentDidUpdate() on the prototype' ); } prototype.componentWillUpdate = componentWillUpdate; var componentDidUpdate = prototype.componentDidUpdate; prototype.componentDidUpdate = function componentDidUpdatePolyfill( prevProps, prevState, maybeSnapshot ) { // 16.3+ will not execute our will-update method; // It will pass a snapshot value to did-update though. // Older versions will require our polyfilled will-update value. // We need to handle both cases, but can't just check for the presence of "maybeSnapshot", // Because for <= 15.x versions this might be a "prevContext" object. // We also can't just check "__reactInternalSnapshot", // Because get-snapshot might return a falsy value. // So check for the explicit __reactInternalSnapshotFlag flag to determine behavior. var snapshot = this.__reactInternalSnapshotFlag ? this.__reactInternalSnapshot : maybeSnapshot; componentDidUpdate.call(this, prevProps, prevState, snapshot); }; } return Component; } var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; 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 inherits = function (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; }; var possibleConstructorReturn = function (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; }; var INITIAL_VALUE_PROP_NAME = 'initialValue'; var createResultStore = function createResultStore(RootConsumer, rootDisplayName) { var _createContext = createContext(), Consumer = _createContext.Consumer, Provider = _createContext.Provider; var Internal = function (_React$Component) { inherits(Internal, _React$Component); function Internal() { var _temp, _this, _ret; classCallCheck(this, Internal); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.state = { hasResult: false, wasResolved: _this.props.resolved }, _this.reset = function (execute) { _this.setState(getResetState(_this.props)); if (execute) { execute(); } }, _temp), possibleConstructorReturn(_this, _ret); } Internal.prototype.componentDidMount = function componentDidMount() { var props = this.props; var resolved = props.resolved; if (resolved || props.hasOwnProperty(INITIAL_VALUE_PROP_NAME)) { this.setState({ hasResult: true, result: resolved ? props.result : props.initialValue, wasResolved: resolved }); } }; Internal.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) { var resolved = nextProps.resolved, reset = nextProps.reset; if (reset) { return _extends({}, getResetState(nextProps), { wasResolved: resolved }); } if (resolved && !prevState.wasResolved) { if (prevState.hasResult) { return { result: nextProps.reduce(prevState.result, nextProps.result), wasResolved: resolved }; } return { hasResult: true, result: nextProps.result, wasResolved: resolved }; } if (resolved !== prevState.wasResolved) { return { wasResolved: resolved }; } return null; }; Internal.prototype.render = function render() { var state = this.state; var props = this.props; var value = _extends({ hasResult: state.hasResult, reset: props.resetFn }, state.hasResult ? { result: state.result } : {}); return React.createElement( Provider, { value: value }, renderChildren(props, value) ); }; return Internal; }(React.Component); var getResetState = function getResetState(props) { return props.hasOwnProperty(INITIAL_VALUE_PROP_NAME) ? { hasResult: true, result: props.initialValue } : { hasResult: false }; }; { Internal.propTypes = { children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired, reduce: PropTypes.func, reset: PropTypes.bool, initialValue: PropTypes.any, resolved: PropTypes.bool, result: PropTypes.any, resetFn: PropTypes.func.isRequired }; } var ResultStoreInternal = polyfill(Internal); /** * Type of `children` function of a {@link AsyncCall.ResultStore} component. * @function ResultStoreChildrenFunction * @param {object} params * @param {boolean} params.hasResult * @param {any=} params.result * @param {ResetFunction} params.reset Function for manual store cleaning. * @returns {ReactNode} Should return rendered React component(s) depending on supplied params. * @remark type definition */ /** * Type of `reduce` property of a {@link AsyncCall.ResultStore} component. * @function ReduceFunction * @param {any} previousResult * @param {any} currentResult * @returns {any} * @remark type definition */ /** * @class * @classdesc * React Component. Implements store of results of sequential async calls. * Useful when you need to accumulate results of async calls (e.g., to glue together sequential calls of server API). * @example * ```jsx * const concatResults = (previousResult, currentResult) => [...previousResult, ...currentResult] * * ... * * <AsyncCall params={{ page: this.state.page }}> * <AsyncCall.ResultStore reduce={concatResults} reset={this.state.page === 0}> * <AsyncCall.ResultStore.HasResult> * {({ result }) => <pre>{JSON.stringify(result)}</pre>} * </AsyncCall.ResultStore.HasResult> * </AsyncCall.ResultStore> * <button onClick={() => this.setState(({ page }) => ({ page: page + 1}))}> * Load more * </button> * <button onClick={() => this.setState({ page: 0 })}> * Reload * </button> * </AsyncCall> * ``` * @property {ResultStoreChildrenFunction | ReactNode} children React children or function that returns rendered result * depending on `hasResult` flag and `result`. * @property {ReduceFunction} reduce Function from previousResult and currentResult to a new result. * Useful, for example, when you need to accumulate sequential async calls * (e.g. for fetching data for infinte page scroll). * @property {any=} initialValue Optional initial value for the result store. If value is provided, result store will have result always. * @property {boolean} [reset=false] @deprecated If `true`, clears the store (**Deprecated, will be removed in version 1.0.0. Use {@link AsyncCall.ResultStore.Resetter} instead**). * @static * @extends {React.Component} * @memberof AsyncCall */ var ResultStore = function (_React$Component2) { inherits(ResultStore, _React$Component2); function ResultStore() { var _temp2, _this2, _ret2; classCallCheck(this, ResultStore); for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return _ret2 = (_temp2 = (_this2 = possibleConstructorReturn(this, _React$Component2.call.apply(_React$Component2, [this].concat(args))), _this2), _this2.reset = function () { var execute = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; _this2.ref.reset(execute && _this2._execute); }, _temp2), possibleConstructorReturn(_this2, _ret2); } ResultStore.prototype.render = function render() { var _this3 = this; return React.createElement( RootConsumer, null, function (context) { invariant(context, INVARIANT_MUST_BE_A_CHILD, ResultStore.displayName, rootDisplayName); warning_1(!_this3.props.hasOwnProperty('reset'), WARNING_PROPERTY_RESET_IS_DEPRECATED); _this3._execute = context.execute; return React.createElement(ResultStoreInternal, _extends({ ref: function ref(_ref) { return _this3.ref = _ref; }, resetFn: _this3.reset }, _this3.props, context)); } ); }; /** * Resets result store to its initial state. * @method * @param {bool} [execute=true] Wether execute promise-returning function after resetting or not. */ return ResultStore; }(React.Component); ResultStore.defaultProps = { reduce: function reduce(_, value) { return value; } }; { ResultStore.propTypes = { children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired, reduce: PropTypes.func, reset: PropTypes.bool, initialValue: PropTypes.any }; ResultStore.displayName = rootDisplayName + '.ResultStore'; ResultStore.Consumer = Consumer; } /** * Type of children function for {@link AsyncCall.ResultStore.HasResult} * @function HasResultChildrenFunction * @param {object} params * @param {any} params.result * @returns {ReactNode} Should return rendered React component(s) depending on supplied params. * @remark type definition */ /** * @class HasResult * @classdesc * React Component. Renders its children whenever result store is not empty (has result). * Property `children` must be a function with the only argument receiving object with the only field `result`. * @example * ```jsx * <AsyncCall.ResultStore.HasResult>{({result}) => <pre>{JSON.stringify(result)}</pre>}</AsyncCall.ResultStore.HasResult> * ``` * @property {HasResultChildrenFunction} children * @static * @extends {React.StatelessComponent} * @memberof AsyncCall.ResultStore */ ResultStore.HasResult = createAsyncCallChild(Consumer, ResultStore.displayName, function (props, contextProps) { return contextProps.hasResult && renderChildrenFn(props, { result: contextProps.result }); }, DISPLAY_NAME_HAS_RESULT, requiredFuncPropType); /** * Reset function * @function ResetFunction * @param {bool} [execute=false] Wether execute promise-returning function after resetting or not. * @remark type definition */ /** * Type of children function for {@link AsyncCall.ResultStore.Resetter} * @function ResetterChildrenFunction * @param {object} params * @param {ResetFunction} params.reset Function for manual clearing of {@link AsyncCall.ResultStore}. * @returns {ReactNode} Should return rendered React component(s) depending on supplied params. * @remark type definition */ /** * @class Resetter * @classdesc * React Component. Renders its children always. Property `children` must be a function with the only argument receiving an object * with a function for manual reset of {@link AsyncCall.ResultStore}. * @example * ```jsx * <AsyncCall.ResultStore.Resetter>{({ reset }) => <button onClick={reset}>Reset</button>}</AsyncCall.ResultStore.Resetter> * ``` * @property {ResetterChildrenFunction} children * @static * @extends {React.StatelessComponent} * @memberof AsyncCall.ResultStore */ ResultStore.Resetter = createAsyncCallChild(Consumer, ResultStore.displayName, function (props, contextProps) { return renderChildrenFn(props, { reset: contextProps.reset }); }, DISPLAY_NAME_RESETTER, requiredFuncPropType); return ResultStore; }; /** * Asynchronous function (aka asynchronous operation or promise-returning function) * which returns promise based on supplied parameter. * @example * The function below returns result (`Promise` object) of getting user data from GitHub API by his/her GitHub login: * ``` * const getGitHubUserData = userName => fetch(`https://api.github.com/users/${userName}`).then(data => data.json()) * ``` * @function AsyncFunction * @param {any} params Parameters, based on which function should return promise. * @returns {Promise} Promise object that represents asynchronous operation result. * @remark type definition */ /** * A factory function that creates React component class and binds async operation to it: * ```jsx * const Fetcher = createAsyncCallComponent(() => fetch('https://api.github.com/repositories').then(data => data.json())) * ``` * * After calling of this function you can use returned component and its static sub-components to hook async operation lifecycle: * * ```jsx * // Start executing async operation on Fetcher mount * <Fetcher> * <Fetcher.Running> * Renders only if async operation is executing * </Fetcher.Running> * * <Fetcher.Resolved> * {({ result }) => ( * <div> * Renders if async operation has been executed successfully * <pre>{JSON.stringify(result)}></pre> * </div> * )}} * </Fetcher.Resolved> * * <Fetcher.Rejected> * Renders only if async operation failed * </Fetcher.Rejected> * </Fetcher> * ``` * * `createAsyncCallComponent` is the only member exported by react-async-call package. * @param {AsyncFunction} fn See [`AsyncFunction` signature]{@link AsyncFunction} for details. * @param {String} [displayName="AsyncCall"] Component name (visible, for example, in React extension of Chrome Dev Tools). * @returns {AsyncCall} Returns React [component class `AsyncCall`]{@link AsyncCall} for the further usage. * This class contains extra component classes [`Running`]{@link AsyncCall.Running}, * [`Rejected`]{@link AsyncCall.Rejected}, [`Resolved`]{@link AsyncCall.Resolved}, * [`Completed`]{@link AsyncCall.Completed}, [`ResultStore`]{@link AsyncCall.ResultStore}, * [`Executor`]{@link AsyncCall.Executor} and [`State`]{@link AsyncCall.State} which can be used as children * (direct or indirect) of `AsyncCall`. * @function */ var createAsyncCallComponent = function createAsyncCallComponent(fn, displayName) { var _createContext = createContext(), Provider = _createContext.Provider, Consumer = _createContext.Consumer; var rootDisplayName = '' + (displayName || 'AsyncCall'); /** * Execute function * @function ExecuteFunction * @returns {void} * @remark type definition */ /** * Type of children function for {@link AsyncCall} * @function AsyncCallChildrenFunction * @param {object} params Represents current status of asynchronous operation. * @param {boolean} params.running Indicates whether asynchronous operation is executing or not. * @param {boolean} params.rejected Indicates whether asynchronous operation was failed when it was called last time. * If `true`, result of promise rejection (error) can be found in the `params.rejectReason`. * @param {boolean} params.resolved Indicates whether asynchronous operation was succeeded when it was called last time. * If `true`, result of promise resolving can be found in the `params.result`. * @param {any=}params.result Contains result of promise (returned by async function) resolving * if function call was successful. `undefined` if asynchronous operation is running or promise was rejected. * @param {any=} params.rejectReason Contains result of promise (returned by async function) rejection * if function call was unsuccessful. `undefined` if asynchronous operation is running or promise was resolved. * @param {ExecuteFunction} params.execute Function for manual execution of asynchronous operation. * @returns {ReactNode} Should return rendered React component(s) depending on supplied params. * @remark type definition */ /** * @classdesc * React Component. This class is returned by call of {@link createAsyncCallComponent} and this is the only way to get it. * @property {ReactNode | AsyncCallChildrenFunction} children Property `children` can be either a ReactNode or * a function that receives an object as its only argument and return ReactNode. * `AsyncCall` component **always** renders its children. We recommend to use * [the first form of using `children` property](https://github.com/kuzn-ilya/react-async-call/blob/master/README.md#basic-usage) * and respond to async operation execution results using *static sub-components* (like [`Running`]{@link AsyncCall.Running}, * [`Rejected`]{@link AsyncCall.Rejected}, [`Resolved`]{@link AsyncCall.Resolved}, * [`Completed`]{@link AsyncCall.Completed}, [`ResultStore`]{@link AsyncCall.ResultStore}, * [`Executor`]{@link AsyncCall.Executor} and [`State`]{@link AsyncCall.State}). * @property {any} params A value that will be passed as a single argument into async function. Every time when change of this property occurs, * asyncronous operation restarts. * @property {Boolean} [lazy=false] If `true`, component will not start execution of asynchronous operation during component mount phase * and on `params` property change. You should start async operation manualy by calling [`execute` method]{@link #AsyncCall+execute} * or via [`Executor`]{@link AsyncCall.Executor}. * @extends {React.Component} */ var AsyncCall = function (_React$Component) { inherits(AsyncCall, _React$Component); function AsyncCall() { var _temp, _this, _ret; classCallCheck(this, AsyncCall); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.state = { running: true, rejected: false, resolved: false }, _this._callQueryFunc = function (params) { _this.setState({ running: true, rejected: false, resolved: false }); var promise = fn(params); invariant(promise && promise.then && isFunction(promise.then), INVARIANT_FUNCTION_SHOULD_RETURN_PROMISE); promise.then(function (result) { if (_this._mounted) { _this.setState({ running: false, rejected: false, resolved: true, result: result }); } }, function (rejectReason) { if (_this._mounted) { _this.setState({ running: false, rejected: true, rejectReason: rejectReason }); } }); }, _this._getState = function () { var _this$state = _this.state, running = _this$state.running, resolved = _this$state.resolved, rejected = _this$state.rejected, result = _this$state.result, rejectReason = _this$state.rejectReason; result = resolved ? { result: result } : {}; rejectReason = rejected ? { rejectReason: rejectReason } : {}; return _extends({ running: running, rejected: rejected, resolved: resolved, execute: _this.execute }, result, rejectReason); }, _this.execute = function () { _this._callQueryFunc(_this.props.params); }, _temp), possibleConstructorReturn(_this, _ret); } /** * @class Running * @classdesc * React Component. Renders its children whenever async operation was started but is still executing. Otherwise renders nothing. * @example * ```jsx * <AsyncCall.Running>Executing...</AsyncCall.Running> * ``` * @property {ReactNode} children * @static * @extends {React.StatelessComponent} * @memberof AsyncCall */ /** * Type of children function for {@link AsyncCall.Resolved} * @function ResolvedChildrenFunction * @param {object} * @param {any} params.result * @returns {ReactNode} Should return rendered React component(s) depending on supplied params. * @remark type definition */ /** * @class Resolved * @classdesc * React Component. Renders its children whenever async operation has been completed successfully (promise was resolved), * but is still not started again. Otherwise renders nothing. * Property `children` can be either React node(s) or children function with the only argument receiving object with the only field `result`. * @example * ```jsx * <AsyncCall.Resolved>Last async operation was successful!</AsyncCall.Resolved> * ``` * * or * * ```jsx * <AsyncCall.Resolved>{({ result }) => <pre>{JSON.stringify(result)}</pre>}</AsyncCall.Resolved> * ``` * @property {ReactNode | ResolvedChildrenFunction} children * @static * @extends {React.StatelessComponent} * @memberof AsyncCall */ /** * Type of children function for {@link AsyncCall.Rejected} * @function RejectedChildrenFunction * @param {object} params * @param {any} params.rejectReason * @returns {ReactNode} Should return rendered React component(s) depending on supplied params. * @remark type definition */ /** * @class Rejected * @static * @classdesc * React Component. Renders its children whenever async operation has been completed with failure (promise was rejected), * but is still not started again. Otherwise renders nothing. * Property `children` can be either React node(s) or children function with the only argument receiving object with the only field `rejectReason` * (promise reject reason). * @example * ```jsx * <AsyncCall.Rejected>Error!</AsyncCall.Rejected> * ``` * * or * ```jsx * <AsyncCall.Rejected>{({ rejectReason }) => Error: {rejectReason}}</AsyncCall.Rejected> * ``` * @property {ReactNode | RejectedChildrenFunction} children * @extends {React.StatelessComponent} * @memberof AsyncCall */ /** * Type of children function for {@link AsyncCall.Executor} * @function ExecutorChildrenFunction * @param {object} params * @param {ExecuteFunction} params.execute Function for manual execution of asynchronous operation. * @returns {ReactNode} Should return rendered React component(s) depending on supplied params. * @remark type definition */ /** * @class Executor * @classdesc * React Component. Renders its children always. Property `children` must be a function with the only argument receiving an object * with a function for manual execution of async operation. * @example * ```jsx * <AsyncCall.Executor>{({ execute }) => <button onClick={execute}>Click me!</button>}</AsyncCall.Executor> * ``` * @property {ExecutorChildrenFunction} children * @static * @extends {React.StatelessComponent} * @memberof AsyncCall */ /** * Type of children function for {@link AsyncCall.State} * @function StateChildrenFunction * @param {object} params * @param {boolean} params.running Whether async opertation is executing or not. * If you only need to process `running`, use either {@link AsyncCall.Running} or {@link AsyncCall.Completed} component instead. * @param {boolean} params.resolved Whether async opertation was completed successfully last time or not. * If you only need to process `resolved` and `result`, {@link AsyncCall.Resolved} component instead. * @param {boolean} params.rejected Whether async opertation failed last time or not. * If you only need to process `rejected` and `rejectedStatus`, use {@link AsyncCall.Rejected} component instead. * @param {any=} params.rejectReason Contains reject reason if async opertation failed last time. * If you only need to process `rejected` and `rejectedReason`, use {@link AsyncCall.Rejected} component instead. * @param {any=} params.result Contains result of last successful async operation call. * If you only need to process `resolved` and `result`, use {@link AsyncCall.Resolved} component instead. * If you need to accumulate result, consider {@link AsyncCall.ResultStore} usage. * @param {ExecuteFunction} params.execute Callback for manual execution of async operation. * If you only need to execute async operation manualy, use {@link AsyncCall.Executor} component instead. | * @returns {ReactNode} Should return rendered React component(s) depending on supplied params. * @remark type definition */ /** * @class State * @classdesc * React Component. Renders its children always. Property `children` must be a function * with the only argument receiving an object ([see description of `StateChildrenFunction`]{@link StateChildrenFunction}) * with the state of async operation. `State` component is handy for complicated UI cases when none of static components of {@link AsyncCall} suits you. * @example * ```jsx * <AsyncCall.State> * {({ running, resolved, result, rejected, rejectReason, execute }) => { * // Something that depends on all of the argument's properties * }} * </AsyncCall.State> * ``` * @property {StateChildrenFunction} children * @static * @extends {React.StatelessComponent} * @memberof AsyncCall */ /** * @class Completed * @classdesc * React Component. Renders its children whenever async operation has been completed (successfully or not), * but is still not started again. Otherwise renders nothing. * * ```jsx * <AsyncCall.Completed> * Async operation completed * </AsyncCall.Completed> * ``` * @property {ReactNode=} children React children to be rendered whenever async operation is completed. * @static * @extends {React.StatelessComponent} * @memberof AsyncCall */ AsyncCall.prototype.componentDidMount = function componentDidMount() { invariant(isFunction(fn), INVARIANT_FUNCTION_SHOULD_BE_PASSED, fn); this._mounted = true; var props = this.props; if (!props.lazy) { this._callQueryFunc(props.params); } }; AsyncCall.prototype.componentWillUnmount = function componentWillUnmount() { this._mounted = false; }; AsyncCall.prototype.componentDidUpdate = function componentDidUpdate(prevProps) { var props = this.props; var params = props.params; if (!props.lazy && !shallowEqual_1(params, prevProps.params)) { this._callQueryFunc(params); } }; /** * Method for executing async operation manually. * It is recommended to use [`<Executor>` component]{@link AsyncCall.Executor} instead. * @method */ AsyncCall.prototype.render = function render() { var state = this._getState(); var props = this.props; return React.createElement( Provider, { value: state }, props.children !== undefined && renderChildren(props, state) ); }; return AsyncCall; }(React.Component); AsyncCall.Running = createAsyncCallChild(Consumer, rootDisplayName, function (props, contextProps) { return contextProps.running && props.children; }, DISPLAY_NAME_RUNNING, nodePropType); AsyncCall.Resolved = createAsyncCallChild(Consumer, rootDisplayName, function (props, contextProps) { return contextProps.resolved && renderChildren(props, { result: contextProps.result }); }, DISPLAY_NAME_RESOLVED, nodeOrFuncPropType); AsyncCall.Rejected = createAsyncCallChild(Consumer, rootDisplayName, function (props, contextProps) { return contextProps.rejected && renderChildren(props, { rejectReason: contextProps.rejectReason }); }, DISPLAY_NAME_REJECTED, nodeOrFuncPropType); AsyncCall.Executor = createAsyncCallChild(Consumer, rootDisplayName, function (props, contextProps) { return renderChildrenFn(props, { execute: contextProps.execute }); }, DISPLAY_NAME_EXECUTOR, requiredFuncPropType); AsyncCall.State = createAsyncCallChild(Consumer, rootDisplayName, renderChildrenFn, DISPLAY_NAME_STATE, requiredFuncPropType); AsyncCall.ResultStore = createResultStore(Consumer, rootDisplayName); AsyncCall.Completed = createAsyncCallChild(Consumer, rootDisplayName, function (props, contextProps) { return (contextProps.resolved || contextProps.rejected) && props.children; }, DISPLAY_NAME_COMPLETED, nodePropType); { AsyncCall.propTypes = { params: PropTyp