UNPKG

@nerdwallet/epic-state-subscriptions

Version:

An epic state subscription library using Redux-Observable

72 lines (54 loc) 4.12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createStateSubscriptionEpics = void 0; var _lodash = _interopRequireDefault(require("lodash")); var _operators = require("rxjs/operators"); var _v = _interopRequireDefault(require("uuid/v4")); var _selectors = require("./selectors"); var _utils = require("./utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // The state subscription path cache records cache entries for each distinct state subscription path the client has configured to watch. // When the state in the cache is different from the current state of the Redux store, a cache miss has occurred // and the client's path operator will receive the updated path in their path stream which they can then process. const stateSubscriptionPathCache = {}; /** * This function wraps the state subscription path operator from each state subcription config * within a state subscription epic that filters updates so that only a stream of paths that they have configured * to watch are sent to the path operators when the path's value changes in the Redux state. * * @param {String} stateSubscriptionEpicConfig.key - The key to use to distinguish each state subscription configuration for the purpose * of dynamic path overrides configurable via the `overrideStateSubscriptionPaths` action * @param {Array} stateSubscriptionEpicConfig.paths - The paths that the client has configured to watch * initiated by the client * @param {Function} stateSubscriptionEpicConfig.pathOperator - The path operator function which takes a stream of updated string paths and performs * the desired client behaviour * @return {Array} - Returns an array of state subscription epics that wrap the path operators provided by the client * configuration which receive the stream of updated path changes */ const createStateSubscriptionEpics = stateSubscriptionConfigs => stateSubscriptionConfigs.map( // Map the state subscription configuration provided by the client to a state subscription epic. stateSubscriptionConfig => (action$, state$) => { const { key, paths: initialSubscriptionPaths, pathOperator } = stateSubscriptionConfig; // default to an arbitrary uuid if the client does not specify a desired key for the state subscription. const subscriptionKey = key || (0, _v.default)(); // Initialize the cache for the state subscription so that an update in the Redux store to that path will // cause a cache miss. stateSubscriptionPathCache[subscriptionKey] = {}; // Modify the stream of actions received by the epic to return a stream of dirty string paths to be handled by the // state subscription path operator. const filteredStateSubscriptionPaths$ = action$.pipe((0, _operators.map)(() => { const currentState = state$.value; const currentStateSubscriptionPathPatterns = (0, _selectors.getStateSubscriptionOverridePaths)(currentState, subscriptionKey) || initialSubscriptionPaths; // Filter the cache to only include entries for patterns that are still being subscribed to, // this way if the formerly subscribed path is re-added, there will be a cache miss const currentStateSubscriptionPathCache = stateSubscriptionPathCache[subscriptionKey]; if (currentStateSubscriptionPathCache) { stateSubscriptionPathCache[subscriptionKey] = _lodash.default.pick(currentStateSubscriptionPathCache, currentStateSubscriptionPathPatterns); } // Paths are collected in the format { path: path, pathPattern: pathPattern } return (0, _utils.findUpdatedStateSubscriptionPaths)(subscriptionKey, stateSubscriptionPathCache, currentStateSubscriptionPathPatterns, currentState); }), (0, _operators.filter)(paths => paths.length > 0)); // Returns the stream that was first processed into paths and then delivered to the client path operator // which executes client logic optionally triggering actions or performing side effects. return pathOperator(filteredStateSubscriptionPaths$, state$); }); exports.createStateSubscriptionEpics = createStateSubscriptionEpics;