UNPKG

cumqueoptio

Version:

The meta-framework suite designed from scratch for frontend-focused modern web development.

122 lines (95 loc) 2.66 kB
import { Store, Model, utils } from '@modern-js-reduck/store'; import { unstable_batchedUpdates } from 'react-dom'; const combineSubscribe = ( store: Store, subscribes: ((handler: () => void) => () => void)[], ) => { let changed = false; const handlers = new Set<any>(); return (handler: () => void) => { handlers.add(handler); const disposer: any[] = []; subscribes.forEach(subscribe => { disposer.push( subscribe(() => { changed = true; }), ); }); const unsubscribeStore = store.subscribe(() => { if (changed) { handlers.forEach(h => h()); } changed = false; }); return () => { unsubscribeStore(); disposer.forEach(dispose => dispose()); }; }; }; const createBatchManager = (store: Store) => { // Models are in using now const usingModelsMap = new Map<Model, number>(); let unsubscribe: undefined | (() => void); const updateList: (() => void)[] = []; // listen to models in using const setupSubscribe = () => { if (typeof unsubscribe === 'function') { unsubscribe(); } const modelSet = new Set<Model>(); for (const [model, count] of usingModelsMap) { if (count !== 0) { modelSet.add(model); } } const subscribe = combineSubscribe( store, [...modelSet].map(m => store.use(m)[2]), ); unsubscribe = subscribe(() => { unstable_batchedUpdates(() => { let update: (() => void) | undefined = updateList.shift(); while (update) { update(); update = updateList.shift(); } }); }); }; const changeModels = (action: 'remove' | 'add', ...models: Model[]) => { models.forEach(model => { if (!utils.isModel(model)) { return; } let usingCount = usingModelsMap.get(model); if (action === 'add') { usingModelsMap.set(model, (usingCount || 0) + 1); } else if (action === 'remove') { if (usingCount) { usingCount -= 1; if (usingCount === 0) { usingModelsMap.delete(model); } else { usingModelsMap.set(model, usingCount); } } } }); setupSubscribe(); }; // add models to listen const addModels = (...args: Model[]) => changeModels('add', ...args); // remove models to listen const removeModels = (...args: Model[]) => changeModels('remove', ...args); const pushUpdate = (update: () => void) => { updateList.push(update); }; return { addModels, removeModels, pushUpdate, }; }; export { createBatchManager };