UNPKG

mobx-keystone

Version:

A MobX powered state management solution based on data trees with first class support for TypeScript, snapshots, patches and much more

90 lines (77 loc) 2.63 kB
import { action } from "mobx" import { ActionContextActionType } from "../action/context" import { HookAction } from "../action/hookActions" import { wrapInAction, wrapModelMethodInActionIfNeeded } from "../action/wrapInAction" import { AnyModel, BaseModel } from "../model/BaseModel" import { walkTree, WalkTreeMode } from "../parent/walkTree" const onAttachedDisposers = new WeakMap<object, () => void>() const attachedToRootStore = new WeakSet<object>() /** * @internal */ export const attachToRootStore = action( "attachToRootStore", (rootStore: object, child: object): void => { // we use an array to ensure they will get called even if the actual hook modifies the tree const childrenToCall: AnyModel[] = [] walkTree( child, (ch) => { // we use this to avoid calling onAttachedToRootStore // twice if (attachedToRootStore.has(ch)) { return } attachedToRootStore.add(ch) if (ch instanceof BaseModel && (ch as any).onAttachedToRootStore) { wrapModelMethodInActionIfNeeded( ch as any, "onAttachedToRootStore", HookAction.OnAttachedToRootStore ) childrenToCall.push(ch as AnyModel) } }, WalkTreeMode.ParentFirst ) const childrenToCallLen = childrenToCall.length for (let i = 0; i < childrenToCallLen; i++) { const ch = childrenToCall[i] const disposer = (ch as any).onAttachedToRootStore(rootStore) if (disposer) { onAttachedDisposers.set(ch, disposer) } } } ) /** * @internal */ export const detachFromRootStore = action("detachFromRootStore", (child: object): void => { // we use an array to ensure they will get called even if the actual hook modifies the tree const disposersToCall: (() => void)[] = [] walkTree( child, (ch) => { if (!attachedToRootStore.delete(ch)) { return } const disposer = onAttachedDisposers.get(ch) if (disposer) { // wrap disposer in action const disposerAction = wrapInAction({ nameOrNameFn: HookAction.OnAttachedToRootStoreDisposer, fn: disposer, actionType: ActionContextActionType.Sync, }).bind(ch) onAttachedDisposers.delete(ch) disposersToCall.push(disposerAction) } }, WalkTreeMode.ChildrenFirst ) const disposersToCallLen = disposersToCall.length for (let i = 0; i < disposersToCallLen; i++) { disposersToCall[i]() } })