UNPKG

@zedux/atoms

Version:

A Molecular State Engine for React

76 lines (75 loc) 2.97 kB
import { createInjector } from '../factories/createInjector.js'; import { haveDepsChanged, prefix } from '../utils/index.js'; const getTask = (effect, descriptor) => { const task = () => { const cleanup = effect(); // now that the task has run, there's no need for the scheduler cleanup // function; replace it with the cleanup logic returned from the effect // (if any). If a promise was returned, ignore it. descriptor.cleanup = typeof cleanup === 'function' ? cleanup : undefined; }; return task; }; /** * Runs a deferred side effect. This is just like React's `useEffect`. When * `deps` change on a subsequent reevaluation, the previous effect will be * cleaned up and the effect will rerun. * * Return a cleanup function to clean up resources when the effect reruns or the * current atom instance is destroyed. * * Unlike `useEffect`, you can return a promise from `injectEffect` (e.g. by * passing an async function). This is only for convenience in cases where you * don't have anything to cleanup, as you'll be unable to clean up resources if * you return a promise. */ export const injectEffect = createInjector('injectEffect', (instance, effect, deps, config) => { const descriptor = { deps, type: `${prefix}/effect`, }; if (!instance.ecosystem.ssr) { const task = getTask(effect, descriptor); descriptor.cleanup = () => { instance.ecosystem._scheduler.unschedule(task); descriptor.cleanup = undefined; }; if (config === null || config === void 0 ? void 0 : config.synchronous) { task(); } else { instance.ecosystem._scheduler.schedule({ task, type: 4, // RunEffect (4) }); } } return descriptor; }, (prevDescriptor, instance, effect, deps, config) => { var _a; if (instance.ecosystem.ssr) return prevDescriptor; const depsHaveChanged = haveDepsChanged(prevDescriptor === null || prevDescriptor === void 0 ? void 0 : prevDescriptor.deps, deps); if (!depsHaveChanged) return prevDescriptor; (_a = prevDescriptor.cleanup) === null || _a === void 0 ? void 0 : _a.call(prevDescriptor); const task = getTask(effect, prevDescriptor); // this cleanup should be unnecessary since effects run immediately every // time except init. Leave this though in case we add a way to update an // atom instance without flushing the scheduler prevDescriptor.cleanup = () => { instance.ecosystem._scheduler.unschedule(task); prevDescriptor.cleanup = undefined; }; prevDescriptor.deps = deps; if (config === null || config === void 0 ? void 0 : config.synchronous) { task(); } else { instance.ecosystem._scheduler.schedule({ task, type: 4, // RunEffect (4) }); } return prevDescriptor; });