diff --git a/src/react/useAtomValue.ts b/src/react/useAtomValue.ts index d46d86f0d7..0ecdc50dcd 100644 --- a/src/react/useAtomValue.ts +++ b/src/react/useAtomValue.ts @@ -1,5 +1,8 @@ import React, { useDebugValue, useEffect, useReducer } from 'react' -import { INTERNAL_getBuildingBlocksRev3 as INTERNAL_getBuildingBlocks } from '../vanilla/internals.ts' +import { + type INTERNAL_BuildingBlockContext, + INTERNAL_getBuildingBlocksRev3 as INTERNAL_getBuildingBlocks, +} from '../vanilla/internals.ts' import type { Atom, ExtractAtomValue } from '../vanilla.ts' import { useStore } from './Provider.ts' @@ -63,6 +66,8 @@ const createContinuablePromise = ( getValue: () => PromiseLike | T, ) => { const buildingBlocks = INTERNAL_getBuildingBlocks(store) + const ctx: INTERNAL_BuildingBlockContext = [...buildingBlocks] as never + ctx.s = store const registerAbortHandler = buildingBlocks[26] let continuablePromise = continuablePromiseMap.get(promise) if (!continuablePromise) { @@ -85,7 +90,7 @@ const createContinuablePromise = ( continuablePromiseMap.set(nextValue, continuablePromise!) curr = nextValue nextValue.then(onFulfilled(nextValue), onRejected(nextValue)) - registerAbortHandler(buildingBlocks, nextValue, onAbort) + registerAbortHandler(ctx, nextValue, onAbort) } else { resolve(nextValue) } @@ -94,7 +99,7 @@ const createContinuablePromise = ( } } promise.then(onFulfilled(promise), onRejected(promise)) - registerAbortHandler(buildingBlocks, promise, onAbort) + registerAbortHandler(ctx, promise, onAbort) }) continuablePromiseMap.set(promise, continuablePromise) } diff --git a/src/vanilla/internals.ts b/src/vanilla/internals.ts index bcef131ce3..48d9ceff4a 100644 --- a/src/vanilla/internals.ts +++ b/src/vanilla/internals.ts @@ -106,69 +106,43 @@ type AtomOnMount = ( ) => OnUnmount | void type EnsureAtomState = ( - buildingBlocks: Readonly, - store: Store, + ctx: BuildingBlockContext, atom: Atom, ) => AtomState -type FlushCallbacks = ( - buildingBlocks: Readonly, - store: Store, -) => void -type RecomputeInvalidatedAtoms = ( - buildingBlocks: Readonly, - store: Store, -) => void +type FlushCallbacks = (ctx: BuildingBlockContext) => void +type RecomputeInvalidatedAtoms = (ctx: BuildingBlockContext) => void type ReadAtomState = ( - buildingBlocks: Readonly, - store: Store, + ctx: BuildingBlockContext, atom: Atom, ) => AtomState -type InvalidateDependents = ( - buildingBlocks: Readonly, - store: Store, - atom: AnyAtom, -) => void +type InvalidateDependents = (ctx: BuildingBlockContext, atom: AnyAtom) => void type WriteAtomState = ( - buildingBlocks: Readonly, - store: Store, + ctx: BuildingBlockContext, atom: WritableAtom, args: Args, ) => Result -type MountDependencies = ( - buildingBlocks: Readonly, - store: Store, - atom: AnyAtom, -) => void +type MountDependencies = (ctx: BuildingBlockContext, atom: AnyAtom) => void type MountAtom = ( - buildingBlocks: Readonly, - store: Store, + ctx: BuildingBlockContext, atom: Atom, ) => Mounted type UnmountAtom = ( - buildingBlocks: Readonly, - store: Store, + ctx: BuildingBlockContext, atom: Atom, ) => Mounted | undefined type SetAtomStateValueOrPromise = ( - buildingBlocks: Readonly, - store: Store, + ctx: BuildingBlockContext, atom: Atom, valueOrPromise: Value, ) => void -type StoreGet = ( - buildingBlocks: Readonly, - store: Store, - atom: Atom, -) => Value +type StoreGet = (ctx: BuildingBlockContext, atom: Atom) => Value type StoreSet = ( - buildingBlocks: Readonly, - store: Store, + ctx: BuildingBlockContext, atom: WritableAtom, ...args: Args ) => Result type StoreSub = ( - buildingBlocks: Readonly, - store: Store, + ctx: BuildingBlockContext, atom: AnyAtom, listener: () => void, ) => () => void @@ -178,12 +152,12 @@ type EnhanceBuildingBlocks = ( ) => Readonly type AbortHandlersMap = WeakMapLike, Set<() => void>> type RegisterAbortHandler = ( - buildingBlocks: Readonly, + ctx: BuildingBlockContext, promise: PromiseLike, abortHandler: () => void, ) => void type AbortPromise = ( - buildingBlocks: Readonly, + ctx: BuildingBlockContext, promise: PromiseLike, ) => void type StoreEpochHolder = [n: EpochNumber] @@ -235,6 +209,8 @@ type BuildingBlocks = [ storeEpochHolder: StoreEpochHolder, // 28 ] +type BuildingBlockContext = BuildingBlocks & { s: Store } + export type { AtomState as INTERNAL_AtomState, Mounted as INTERNAL_Mounted, @@ -258,6 +234,7 @@ export type { UnmountAtom as INTERNAL_UnmountAtom, Store as INTERNAL_Store, BuildingBlocks as INTERNAL_BuildingBlocks, + BuildingBlockContext as INTERNAL_BuildingBlockContext, StoreHooks as INTERNAL_StoreHooks, } @@ -426,14 +403,11 @@ const BUILDING_BLOCK_atomOnInit: AtomOnInit = (store, atom) => const BUILDING_BLOCK_atomOnMount: AtomOnMount = (_store, atom, setAtom) => atom.onMount?.(setAtom) -const BUILDING_BLOCK_ensureAtomState: EnsureAtomState = ( - buildingBlocks, - store, - atom, -) => { - const atomStateMap = buildingBlocks[0] - const storeHooks = buildingBlocks[6] - const atomOnInit = buildingBlocks[9] +const BUILDING_BLOCK_ensureAtomState: EnsureAtomState = (ctx, atom) => { + const atomStateMap = ctx[0] + const storeHooks = ctx[6] + const atomOnInit = ctx[9] + const store = ctx.s if (import.meta.env?.MODE !== 'production' && !atom) { throw new Error('Atom is undefined or null') } @@ -447,16 +421,13 @@ const BUILDING_BLOCK_ensureAtomState: EnsureAtomState = ( return atomState as never } -const BUILDING_BLOCK_flushCallbacks: FlushCallbacks = ( - buildingBlocks, - store, -) => { - const mountedMap = buildingBlocks[1] - const changedAtoms = buildingBlocks[3] - const mountCallbacks = buildingBlocks[4] - const unmountCallbacks = buildingBlocks[5] - const storeHooks = buildingBlocks[6] - const recomputeInvalidatedAtoms = buildingBlocks[13] +const BUILDING_BLOCK_flushCallbacks: FlushCallbacks = (ctx) => { + const mountedMap = ctx[1] + const changedAtoms = ctx[3] + const mountCallbacks = ctx[4] + const unmountCallbacks = ctx[5] + const storeHooks = ctx[6] + const recomputeInvalidatedAtoms = ctx[13] if ( !storeHooks.f && !changedAtoms.size && @@ -499,7 +470,7 @@ const BUILDING_BLOCK_flushCallbacks: FlushCallbacks = ( call(fn) } if (changedAtoms.size) { - recomputeInvalidatedAtoms(buildingBlocks, store) + recomputeInvalidatedAtoms(ctx) } } while (changedAtoms.size || unmountCallbacks.size || mountCallbacks.size) if (errors.length) { @@ -508,15 +479,14 @@ const BUILDING_BLOCK_flushCallbacks: FlushCallbacks = ( } const BUILDING_BLOCK_recomputeInvalidatedAtoms: RecomputeInvalidatedAtoms = ( - buildingBlocks, - store, + ctx, ) => { - const mountedMap = buildingBlocks[1] - const invalidatedAtoms = buildingBlocks[2] - const changedAtoms = buildingBlocks[3] - const ensureAtomState = buildingBlocks[11] - const readAtomState = buildingBlocks[14] - const mountDependencies = buildingBlocks[17] + const mountedMap = ctx[1] + const invalidatedAtoms = ctx[2] + const changedAtoms = ctx[3] + const ensureAtomState = ctx[11] + const readAtomState = ctx[14] + const mountDependencies = ctx[17] if (!changedAtoms.size) { return } @@ -535,7 +505,7 @@ const BUILDING_BLOCK_recomputeInvalidatedAtoms: RecomputeInvalidatedAtoms = ( // without incoming edges, which is one reason we can simplify the algorithm for (const atom of changedAtoms) { stackAtoms.push(atom) - stackStates.push(ensureAtomState(buildingBlocks, store, atom)) + stackStates.push(ensureAtomState(ctx, atom)) } while (stackAtoms.length) { const top = stackAtoms.length - 1 @@ -571,7 +541,7 @@ const BUILDING_BLOCK_recomputeInvalidatedAtoms: RecomputeInvalidatedAtoms = ( for (const d of getMountedOrPendingDependents(a, aState, mountedMap)) { if (!visiting.has(d)) { stackAtoms.push(d) - stackStates.push(ensureAtomState(buildingBlocks, store, d)) + stackStates.push(ensureAtomState(ctx, d)) } } } @@ -589,8 +559,8 @@ const BUILDING_BLOCK_recomputeInvalidatedAtoms: RecomputeInvalidatedAtoms = ( } if (hasChangedDeps) { invalidatedAtoms.set(a, aState.n) - readAtomState(buildingBlocks, store, a) - mountDependencies(buildingBlocks, store, a) + readAtomState(ctx, a) + mountDependencies(ctx, a) } invalidatedAtoms.delete(a) } @@ -599,26 +569,23 @@ const BUILDING_BLOCK_recomputeInvalidatedAtoms: RecomputeInvalidatedAtoms = ( // Dev only const storeMutationSet = new WeakSet() -const BUILDING_BLOCK_readAtomState: ReadAtomState = ( - buildingBlocks, - store, - atom, -) => { - const mountedMap = buildingBlocks[1] - const invalidatedAtoms = buildingBlocks[2] - const changedAtoms = buildingBlocks[3] - const storeHooks = buildingBlocks[6] - const atomRead = buildingBlocks[7] - const ensureAtomState = buildingBlocks[11] - const flushCallbacks = buildingBlocks[12] - const recomputeInvalidatedAtoms = buildingBlocks[13] - const readAtomState = buildingBlocks[14] - const writeAtomState = buildingBlocks[16] - const mountDependencies = buildingBlocks[17] - const setAtomStateValueOrPromise = buildingBlocks[20] - const registerAbortHandler = buildingBlocks[26] - const storeEpochHolder = buildingBlocks[28] - const atomState = ensureAtomState(buildingBlocks, store, atom) +const BUILDING_BLOCK_readAtomState: ReadAtomState = (ctx, atom) => { + const mountedMap = ctx[1] + const invalidatedAtoms = ctx[2] + const changedAtoms = ctx[3] + const storeHooks = ctx[6] + const atomRead = ctx[7] + const ensureAtomState = ctx[11] + const flushCallbacks = ctx[12] + const recomputeInvalidatedAtoms = ctx[13] + const readAtomState = ctx[14] + const writeAtomState = ctx[16] + const mountDependencies = ctx[17] + const setAtomStateValueOrPromise = ctx[20] + const registerAbortHandler = ctx[26] + const storeEpochHolder = ctx[28] + const store = ctx.s + const atomState = ensureAtomState(ctx, atom) const storeEpochNumber = storeEpochHolder[0] // See if we can skip recomputing this atom. if (isAtomStateInitialized(atomState)) { @@ -638,7 +605,7 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = ( // If all dependencies haven't changed, we can use the cache. let hasChangedDeps = false for (const [a, n] of atomState.d) { - if (readAtomState(buildingBlocks, store, a).n !== n) { + if (readAtomState(ctx, a).n !== n) { hasChangedDeps = true break } @@ -660,19 +627,19 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = ( if (mountedMap.has(atom)) { // If changedAtoms is already populated, an outer recompute cycle will handle it const shouldRecompute = !changedAtoms.size - mountDependencies(buildingBlocks, store, atom) + mountDependencies(ctx, atom) if (shouldRecompute) { - recomputeInvalidatedAtoms(buildingBlocks, store) - flushCallbacks(buildingBlocks, store) + recomputeInvalidatedAtoms(ctx) + flushCallbacks(ctx) } } } const getter = (a: Atom) => { if (a === (atom as AnyAtom)) { - const aState = ensureAtomState(buildingBlocks, store, a) + const aState = ensureAtomState(ctx, a) if (!isAtomStateInitialized(aState)) { if (hasInitialValue(a)) { - setAtomStateValueOrPromise(buildingBlocks, store, a, a.init) + setAtomStateValueOrPromise(ctx, a, a.init) } else { // NOTE invalid derived atoms can reach here throw new Error('no atom init') @@ -681,7 +648,7 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = ( return returnAtomValue(aState) } // a !== atom - const aState = readAtomState(buildingBlocks, store, a) + const aState = readAtomState(ctx, a) try { return returnAtomValue(aState) } finally { @@ -727,10 +694,10 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = ( } if (!isSync) { try { - return writeAtomState(buildingBlocks, store, atom, args) + return writeAtomState(ctx, atom, args) } finally { - recomputeInvalidatedAtoms(buildingBlocks, store) - flushCallbacks(buildingBlocks, store) + recomputeInvalidatedAtoms(ctx) + flushCallbacks(ctx) } } } @@ -750,11 +717,9 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = ( 'Detected store mutation during atom read. This is not supported.', ) } - setAtomStateValueOrPromise(buildingBlocks, store, atom, valueOrPromise) + setAtomStateValueOrPromise(ctx, atom, valueOrPromise) if (isPromiseLike(valueOrPromise)) { - registerAbortHandler(buildingBlocks, valueOrPromise, () => - controller?.abort(), - ) + registerAbortHandler(ctx, valueOrPromise, () => controller?.abort()) const settle = () => { pruneDependencies() mountDependenciesIfAsync() @@ -783,19 +748,18 @@ const BUILDING_BLOCK_readAtomState: ReadAtomState = ( } const BUILDING_BLOCK_invalidateDependents: InvalidateDependents = ( - buildingBlocks, - store, + ctx, atom, ) => { - const mountedMap = buildingBlocks[1] - const invalidatedAtoms = buildingBlocks[2] - const ensureAtomState = buildingBlocks[11] + const mountedMap = ctx[1] + const invalidatedAtoms = ctx[2] + const ensureAtomState = ctx[11] const stack: AnyAtom[] = [atom] while (stack.length) { const a = stack.pop()! - const aState = ensureAtomState(buildingBlocks, store, a) + const aState = ensureAtomState(ctx, a) for (const d of getMountedOrPendingDependents(a, aState, mountedMap)) { - const dState = ensureAtomState(buildingBlocks, store, d) + const dState = ensureAtomState(ctx, d) if (invalidatedAtoms.get(d) !== dState.n) { invalidatedAtoms.set(d, dState.n) stack.push(d) @@ -804,32 +768,28 @@ const BUILDING_BLOCK_invalidateDependents: InvalidateDependents = ( } } -const BUILDING_BLOCK_writeAtomState: WriteAtomState = ( - buildingBlocks, - store, - atom, - args, -) => { - const changedAtoms = buildingBlocks[3] - const storeHooks = buildingBlocks[6] - const atomWrite = buildingBlocks[8] - const ensureAtomState = buildingBlocks[11] - const flushCallbacks = buildingBlocks[12] - const recomputeInvalidatedAtoms = buildingBlocks[13] - const readAtomState = buildingBlocks[14] - const invalidateDependents = buildingBlocks[15] - const writeAtomState = buildingBlocks[16] - const mountDependencies = buildingBlocks[17] - const setAtomStateValueOrPromise = buildingBlocks[20] - const storeEpochHolder = buildingBlocks[28] +const BUILDING_BLOCK_writeAtomState: WriteAtomState = (ctx, atom, args) => { + const changedAtoms = ctx[3] + const storeHooks = ctx[6] + const atomWrite = ctx[8] + const ensureAtomState = ctx[11] + const flushCallbacks = ctx[12] + const recomputeInvalidatedAtoms = ctx[13] + const readAtomState = ctx[14] + const invalidateDependents = ctx[15] + const writeAtomState = ctx[16] + const mountDependencies = ctx[17] + const setAtomStateValueOrPromise = ctx[20] + const storeEpochHolder = ctx[28] + const store = ctx.s let isSync = true const getter: Getter = (a: Atom) => - returnAtomValue(readAtomState(buildingBlocks, store, a)) + returnAtomValue(readAtomState(ctx, a)) const setter: Setter = ( a: WritableAtom, ...args: As ) => { - const aState = ensureAtomState(buildingBlocks, store, a) + const aState = ensureAtomState(ctx, a) try { if (a === (atom as AnyAtom)) { if (!hasInitialValue(a)) { @@ -841,22 +801,22 @@ const BUILDING_BLOCK_writeAtomState: WriteAtomState = ( } const prevEpochNumber = aState.n const v = args[0] as V - setAtomStateValueOrPromise(buildingBlocks, store, a, v) - mountDependencies(buildingBlocks, store, a) + setAtomStateValueOrPromise(ctx, a, v) + mountDependencies(ctx, a) if (prevEpochNumber !== aState.n) { ++storeEpochHolder[0] changedAtoms.add(a) - invalidateDependents(buildingBlocks, store, a) + invalidateDependents(ctx, a) storeHooks.c?.(a) } return undefined as R } else { - return writeAtomState(buildingBlocks, store, a, args) + return writeAtomState(ctx, a, args) } } finally { if (!isSync) { - recomputeInvalidatedAtoms(buildingBlocks, store) - flushCallbacks(buildingBlocks, store) + recomputeInvalidatedAtoms(ctx) + flushCallbacks(ctx) } } } @@ -867,30 +827,26 @@ const BUILDING_BLOCK_writeAtomState: WriteAtomState = ( } } -const BUILDING_BLOCK_mountDependencies: MountDependencies = ( - buildingBlocks, - store, - atom, -) => { - const mountedMap = buildingBlocks[1] - const changedAtoms = buildingBlocks[3] - const storeHooks = buildingBlocks[6] - const ensureAtomState = buildingBlocks[11] - const invalidateDependents = buildingBlocks[15] - const mountAtom = buildingBlocks[18] - const unmountAtom = buildingBlocks[19] - const atomState = ensureAtomState(buildingBlocks, store, atom) +const BUILDING_BLOCK_mountDependencies: MountDependencies = (ctx, atom) => { + const mountedMap = ctx[1] + const changedAtoms = ctx[3] + const storeHooks = ctx[6] + const ensureAtomState = ctx[11] + const invalidateDependents = ctx[15] + const mountAtom = ctx[18] + const unmountAtom = ctx[19] + const atomState = ensureAtomState(ctx, atom) const mounted = mountedMap.get(atom) if (mounted && atomState.d.size > 0) { for (const [a, n] of atomState.d) { if (!mounted.d.has(a)) { - const aState = ensureAtomState(buildingBlocks, store, a) - const aMounted = mountAtom(buildingBlocks, store, a) + const aState = ensureAtomState(ctx, a) + const aMounted = mountAtom(ctx, a) aMounted.t.add(atom) mounted.d.add(a) if (n !== aState.n) { changedAtoms.add(a) - invalidateDependents(buildingBlocks, store, a) + invalidateDependents(ctx, a) storeHooks.c?.(a) } } @@ -898,32 +854,33 @@ const BUILDING_BLOCK_mountDependencies: MountDependencies = ( for (const a of mounted.d) { if (!atomState.d.has(a)) { mounted.d.delete(a) - const aMounted = unmountAtom(buildingBlocks, store, a) + const aMounted = unmountAtom(ctx, a) aMounted?.t.delete(atom) } } } } -const BUILDING_BLOCK_mountAtom: MountAtom = (buildingBlocks, store, atom) => { - const mountedMap = buildingBlocks[1] - const mountCallbacks = buildingBlocks[4] - const storeHooks = buildingBlocks[6] - const atomOnMount = buildingBlocks[10] - const ensureAtomState = buildingBlocks[11] - const flushCallbacks = buildingBlocks[12] - const recomputeInvalidatedAtoms = buildingBlocks[13] - const readAtomState = buildingBlocks[14] - const writeAtomState = buildingBlocks[16] - const mountAtom = buildingBlocks[18] - const atomState = ensureAtomState(buildingBlocks, store, atom) +const BUILDING_BLOCK_mountAtom: MountAtom = (ctx, atom) => { + const mountedMap = ctx[1] + const mountCallbacks = ctx[4] + const storeHooks = ctx[6] + const atomOnMount = ctx[10] + const ensureAtomState = ctx[11] + const flushCallbacks = ctx[12] + const recomputeInvalidatedAtoms = ctx[13] + const readAtomState = ctx[14] + const writeAtomState = ctx[16] + const mountAtom = ctx[18] + const store = ctx.s + const atomState = ensureAtomState(ctx, atom) let mounted = mountedMap.get(atom) if (!mounted) { // recompute atom state - readAtomState(buildingBlocks, store, atom) + readAtomState(ctx, atom) // mount dependencies first for (const a of atomState.d.keys()) { - const aMounted = mountAtom(buildingBlocks, store, a) + const aMounted = mountAtom(ctx, a) aMounted.t.add(atom) } // mount self @@ -938,11 +895,11 @@ const BUILDING_BLOCK_mountAtom: MountAtom = (buildingBlocks, store, atom) => { let isSync = true const setAtom = (...args: unknown[]) => { try { - return writeAtomState(buildingBlocks, store, atom, args) + return writeAtomState(ctx, atom, args) } finally { if (!isSync) { - recomputeInvalidatedAtoms(buildingBlocks, store) - flushCallbacks(buildingBlocks, store) + recomputeInvalidatedAtoms(ctx) + flushCallbacks(ctx) } } } @@ -969,17 +926,13 @@ const BUILDING_BLOCK_mountAtom: MountAtom = (buildingBlocks, store, atom) => { return mounted } -const BUILDING_BLOCK_unmountAtom: UnmountAtom = ( - buildingBlocks, - store, - atom, -) => { - const mountedMap = buildingBlocks[1] - const unmountCallbacks = buildingBlocks[5] - const storeHooks = buildingBlocks[6] - const ensureAtomState = buildingBlocks[11] - const unmountAtom = buildingBlocks[19] - const atomState = ensureAtomState(buildingBlocks, store, atom) +const BUILDING_BLOCK_unmountAtom: UnmountAtom = (ctx, atom) => { + const mountedMap = ctx[1] + const unmountCallbacks = ctx[5] + const storeHooks = ctx[6] + const ensureAtomState = ctx[11] + const unmountAtom = ctx[19] + const atomState = ensureAtomState(ctx, atom) let mounted = mountedMap.get(atom) if (!mounted || mounted.l.size) { return mounted @@ -1000,7 +953,7 @@ const BUILDING_BLOCK_unmountAtom: UnmountAtom = ( mountedMap.delete(atom) // unmount dependencies for (const a of atomState.d.keys()) { - const aMounted = unmountAtom(buildingBlocks, store, a) + const aMounted = unmountAtom(ctx, a) aMounted?.t.delete(atom) } storeHooks.u?.(atom) @@ -1010,14 +963,13 @@ const BUILDING_BLOCK_unmountAtom: UnmountAtom = ( } const BUILDING_BLOCK_setAtomStateValueOrPromise: SetAtomStateValueOrPromise = ( - buildingBlocks, - store, + ctx, atom, valueOrPromise, ) => { - const ensureAtomState = buildingBlocks[11] - const abortPromise = buildingBlocks[27] - const atomState = ensureAtomState(buildingBlocks, store, atom) + const ensureAtomState = ctx[11] + const abortPromise = ctx[27] + const atomState = ensureAtomState(ctx, atom) const hasPrevValue = 'v' in atomState const prevValue = atomState.v if (isPromiseLike(valueOrPromise)) { @@ -1025,7 +977,7 @@ const BUILDING_BLOCK_setAtomStateValueOrPromise: SetAtomStateValueOrPromise = ( addPendingPromiseToDependency( atom, valueOrPromise, - ensureAtomState(buildingBlocks, store, a), + ensureAtomState(ctx, a), ) } } @@ -1034,63 +986,53 @@ const BUILDING_BLOCK_setAtomStateValueOrPromise: SetAtomStateValueOrPromise = ( if (!hasPrevValue || !Object.is(prevValue, atomState.v)) { ++atomState.n if (isPromiseLike(prevValue)) { - abortPromise(buildingBlocks, prevValue) + abortPromise(ctx, prevValue) } } } -const BUILDING_BLOCK_storeGet: StoreGet = (buildingBlocks, store, atom) => { - const readAtomState = buildingBlocks[14] - return returnAtomValue(readAtomState(buildingBlocks, store, atom)) +const BUILDING_BLOCK_storeGet: StoreGet = (ctx, atom) => { + const readAtomState = ctx[14] + return returnAtomValue(readAtomState(ctx, atom)) } -const BUILDING_BLOCK_storeSet: StoreSet = ( - buildingBlocks, - store, - atom, - ...args -) => { - const changedAtoms = buildingBlocks[3] - const flushCallbacks = buildingBlocks[12] - const recomputeInvalidatedAtoms = buildingBlocks[13] - const writeAtomState = buildingBlocks[16] +const BUILDING_BLOCK_storeSet: StoreSet = (ctx, atom, ...args) => { + const changedAtoms = ctx[3] + const flushCallbacks = ctx[12] + const recomputeInvalidatedAtoms = ctx[13] + const writeAtomState = ctx[16] const prevChangedAtomsSize = changedAtoms.size try { - return writeAtomState(buildingBlocks, store, atom, args) + return writeAtomState(ctx, atom, args) } finally { if (changedAtoms.size !== prevChangedAtomsSize) { - recomputeInvalidatedAtoms(buildingBlocks, store) - flushCallbacks(buildingBlocks, store) + recomputeInvalidatedAtoms(ctx) + flushCallbacks(ctx) } } } -const BUILDING_BLOCK_storeSub: StoreSub = ( - buildingBlocks, - store, - atom, - listener, -) => { - const flushCallbacks = buildingBlocks[12] - const mountAtom = buildingBlocks[18] - const unmountAtom = buildingBlocks[19] - const mounted = mountAtom(buildingBlocks, store, atom) +const BUILDING_BLOCK_storeSub: StoreSub = (ctx, atom, listener) => { + const flushCallbacks = ctx[12] + const mountAtom = ctx[18] + const unmountAtom = ctx[19] + const mounted = mountAtom(ctx, atom) const listeners = mounted.l listeners.add(listener) - flushCallbacks(buildingBlocks, store) + flushCallbacks(ctx) return () => { listeners.delete(listener) - unmountAtom(buildingBlocks, store, atom) - flushCallbacks(buildingBlocks, store) + unmountAtom(ctx, atom) + flushCallbacks(ctx) } } const BUILDING_BLOCK_registerAbortHandler: RegisterAbortHandler = ( - buildingBlocks, + ctx, promise, abortHandler, ) => { - const abortHandlersMap = buildingBlocks[25] + const abortHandlersMap = ctx[25] let abortHandlers = abortHandlersMap.get(promise) if (!abortHandlers) { abortHandlers = new Set() @@ -1101,8 +1043,8 @@ const BUILDING_BLOCK_registerAbortHandler: RegisterAbortHandler = ( abortHandlers.add(abortHandler) } -const BUILDING_BLOCK_abortPromise: AbortPromise = (buildingBlocks, promise) => { - const abortHandlersMap = buildingBlocks[25] +const BUILDING_BLOCK_abortPromise: AbortPromise = (ctx, promise) => { + const abortHandlersMap = ctx[25] const abortHandlers = abortHandlersMap.get(promise) abortHandlers?.forEach((fn) => fn()) } @@ -1126,13 +1068,13 @@ function getBuildingBlocks(store: Store): Readonly { function buildStore(...partialBuildingBlocks: Partial): Store { const store: Store = { get(atom) { - return storeGet(buildingBlocks, store, atom) + return storeGet(ctx, atom) }, set(atom, ...args) { - return storeSet(buildingBlocks, store, atom, ...args) + return storeSet(ctx, atom, ...args) }, sub(atom, listener) { - return storeSub(buildingBlocks, store, atom, listener) + return storeSub(ctx, atom, listener) }, } @@ -1178,6 +1120,8 @@ function buildStore(...partialBuildingBlocks: Partial): Store { const storeGet = buildingBlocks[21] const storeSet = buildingBlocks[22] const storeSub = buildingBlocks[23] + const ctx: BuildingBlockContext = [...buildingBlocks] as never + ctx.s = store return store } diff --git a/tests/vanilla/internals.test.tsx b/tests/vanilla/internals.test.tsx index 0b1005b162..3eba6c46c0 100644 --- a/tests/vanilla/internals.test.tsx +++ b/tests/vanilla/internals.test.tsx @@ -3,6 +3,7 @@ import { atom, createStore } from 'jotai' import type { INTERNAL_AtomState, INTERNAL_AtomStateMap, + INTERNAL_BuildingBlockContext, INTERNAL_BuildingBlocks, INTERNAL_InvalidatedAtoms, } from 'jotai/vanilla/internals' @@ -215,9 +216,9 @@ describe('internals', () => { const unsub = store.sub(leafAtom, () => {}) const buildingBlocks = INTERNAL_getBuildingBlocks(store) const invalidateDependents = buildingBlocks[15] - expect(() => - invalidateDependents(buildingBlocks, store, baseAtom), - ).not.toThrow() + const ctx: INTERNAL_BuildingBlockContext = [...buildingBlocks] as never + ctx.s = store + expect(() => invalidateDependents(ctx, baseAtom)).not.toThrow() unsub() }) })