UNPKG

@zedux/core

Version:

A high-level, declarative, composable form of Redux

61 lines (60 loc) 2.5 kB
import { getMetaData, removeMeta } from '../api/meta.js'; import { zeduxTypes } from '../api/zeduxTypes.js'; import { BranchNodeType, StoreNodeType } from '../utils/general.js'; const getErrorMessage = (subStorePath) => `Zedux: store.dispatch() - Invalid Delegation - Store does not contain a child store at path: ${subStorePath.join(' -> ')}`; const prodError = 'Minified Error'; /** * Finds a node in a tree given a node path (array of nodes). */ const findChild = (tree, nodePath) => { for (const node of nodePath) { if (tree.type !== BranchNodeType) { throw new ReferenceError(true /* DEV */ ? getErrorMessage(nodePath) : prodError); } tree = tree.children[node]; if (!tree) { throw new ReferenceError(true /* DEV */ ? getErrorMessage(nodePath) : prodError); } } return tree; }; /** * Delegates an action to a child store. * * Does nothing if the special `delegate` meta node is not present in the action * chain. * * This expects the `metaData` of the `delegate` meta node to be an array * containing a path of nodes describing the child store's location in the * parent store's current hierarchy descriptor. * * Delegated actions will not be handled by the parent store at all. */ export const delegate = (tree, action) => { const subStorePath = getMetaData(action, zeduxTypes.delegate); if (!subStorePath || !tree) return false; const child = findChild(tree, subStorePath); if (child.type !== StoreNodeType) { throw new TypeError(true /* DEV */ ? getErrorMessage(subStorePath) : prodError); } ; child.store.dispatch(removeMeta(action, zeduxTypes.delegate)); }; /** * Propagates a state change from a child store to a parent. * * Recursively finds the child store's node in the parent store's state tree and * re-creates all the nodes down that path. * * #immutability */ export const propagateChange = (currentState, subStorePath, newSubStoreState, hierarchyConfig) => { if (!subStorePath.length) return newSubStoreState; // at this point we can assume that currentState is a hierarhical structure // these "currentState as any" casts should be fine const newNode = hierarchyConfig.clone(currentState); const nextNodeKey = subStorePath[0]; return hierarchyConfig.set(newNode, nextNodeKey, propagateChange(hierarchyConfig.get(currentState, nextNodeKey), subStorePath.slice(1), newSubStoreState, hierarchyConfig)); };