From 26ad928b69d626341ac28aa7146a24ad7561f1e9 Mon Sep 17 00:00:00 2001 From: Corbin Crutchley Date: Mon, 2 Dec 2024 03:33:25 -0800 Subject: [PATCH 1/8] chore: initial work to refactor away from Derived having an internal Store --- packages/store/src/derived.ts | 72 ++++++++++++++--------------------- packages/store/src/effect.ts | 2 +- 2 files changed, 29 insertions(+), 45 deletions(-) diff --git a/packages/store/src/derived.ts b/packages/store/src/derived.ts index d11177e..c0a2b59 100644 --- a/packages/store/src/derived.ts +++ b/packages/store/src/derived.ts @@ -51,24 +51,15 @@ export interface DerivedOptions< fn: (props: DerivedFnProps) => TState } -export interface DerivedMountOptions { - /** - * Should recompute the value on mount? - * @default {true} - */ - recompute?: boolean -} - export class Derived< TState, const TArr extends ReadonlyArray< Derived | Store > = ReadonlyArray, > { - /** - * @private - */ - _store: Store + listeners = new Set>() + state: TState + prevState: TState | undefined options: DerivedOptions /** @@ -87,35 +78,17 @@ export class Derived< return { prevDepVals: prevDepVals as never, currDepVals: currDepVals as never, - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - prevVal: this._store?.prevState ?? undefined, + prevVal: this.prevState ?? undefined, } } constructor(options: DerivedOptions) { this.options = options - const initVal = options.fn({ + this.state = options.fn({ prevDepVals: undefined, prevVal: undefined, currDepVals: this.getDepVals().currDepVals, }) - - this._store = new Store(initVal, { - onSubscribe: options.onSubscribe?.bind(this) as never, - onUpdate: options.onUpdate, - }) - } - - get state() { - return this._store.state - } - - set prevState(val: TState) { - this._store.prevState = val - } - - get prevState() { - return this._store.prevState } registerOnGraph( @@ -168,21 +141,27 @@ export class Derived< } recompute = () => { - this._store.setState(() => { - const { prevDepVals, currDepVals, prevVal } = this.getDepVals() - return this.options.fn({ - prevDepVals, - currDepVals, - prevVal, - }) + const { prevDepVals, currDepVals, prevVal } = this.getDepVals() + this.prevState = this.state + this.state = this.options.fn({ + prevDepVals, + currDepVals, + prevVal, }) + + // Always run onUpdate, regardless of batching + this.options.onUpdate?.() + + for (const listener of this.listeners) { + listener({ + prevVal: this.prevState as never, + currentVal: this.state as never, + }) + } } - mount = ({ recompute = true }: DerivedMountOptions = {}) => { + mount = () => { this.registerOnGraph() - if (recompute) { - this.recompute() - } return () => { this.unregisterFromGraph() @@ -193,6 +172,11 @@ export class Derived< } subscribe = (listener: Listener) => { - return this._store.subscribe(listener) + this.listeners.add(listener) + const unsub = this.options.onSubscribe?.(listener, this) + return () => { + this.listeners.delete(listener) + unsub?.() + } } } diff --git a/packages/store/src/effect.ts b/packages/store/src/effect.ts index 6615fbd..cbb647c 100644 --- a/packages/store/src/effect.ts +++ b/packages/store/src/effect.ts @@ -37,6 +37,6 @@ export class Effect { } mount() { - return this._derived.mount({ recompute: false }) + return this._derived.mount() } } From cf51e7dc18a2b1770ba1892dcfd16d837700c7ad Mon Sep 17 00:00:00 2001 From: Corbin Crutchley Date: Mon, 2 Dec 2024 03:37:26 -0800 Subject: [PATCH 2/8] chore: test refactor of Derived to not include a Store --- packages/store/src/derived.ts | 9 +------- packages/store/src/scheduler.ts | 38 +++++++++++++++++++++++++-------- packages/store/src/store.ts | 6 +++--- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/packages/store/src/derived.ts b/packages/store/src/derived.ts index c0a2b59..be67a2e 100644 --- a/packages/store/src/derived.ts +++ b/packages/store/src/derived.ts @@ -141,8 +141,8 @@ export class Derived< } recompute = () => { - const { prevDepVals, currDepVals, prevVal } = this.getDepVals() this.prevState = this.state + const { prevDepVals, currDepVals, prevVal } = this.getDepVals() this.state = this.options.fn({ prevDepVals, currDepVals, @@ -151,13 +151,6 @@ export class Derived< // Always run onUpdate, regardless of batching this.options.onUpdate?.() - - for (const listener of this.listeners) { - listener({ - prevVal: this.prevState as never, - currentVal: this.state as never, - }) - } } mount = () => { diff --git a/packages/store/src/scheduler.ts b/packages/store/src/scheduler.ts index 84d439f..0e05e0e 100644 --- a/packages/store/src/scheduler.ts +++ b/packages/store/src/scheduler.ts @@ -53,6 +53,24 @@ function __flush_internals(relatedVals: Set>) { } } +function __notifyListeners(store: Store) { + store.listeners.forEach((listener) => + listener({ + prevVal: store.prevState as never, + currentVal: store.state as never, + }), + ) +} + +function __notifyDerivedListeners(derived: Derived) { + derived.listeners.forEach((listener) => + listener({ + prevVal: derived.prevState as never, + currentVal: derived.state as never, + }), + ) +} + /** * @private only to be called from `Store` on write */ @@ -71,12 +89,7 @@ export function __flush(store: Store) { // First notify listeners with updated values for (const store of stores) { - store.listeners.forEach((listener) => - listener({ - prevVal: store.prevState as never, - currentVal: store.state as never, - }), - ) + __notifyListeners(store) } // Then update all derived values @@ -87,12 +100,19 @@ export function __flush(store: Store) { __depsThatHaveWrittenThisTick.current.push(store) __flush_internals(derivedVals) } + + // Notify derived listeners after recomputing + for (const store of stores) { + const derivedVals = __storeToDerived.get(store) + if (!derivedVals) continue + + for (const derived of derivedVals) { + __notifyDerivedListeners(derived) + } + } } } finally { __isFlushing = false - __depsThatHaveWrittenThisTick.current.forEach((dep) => { - dep.prevState = dep.state - }) __depsThatHaveWrittenThisTick.current = [] } } diff --git a/packages/store/src/store.ts b/packages/store/src/store.ts index a79f855..078af36 100644 --- a/packages/store/src/store.ts +++ b/packages/store/src/store.ts @@ -49,10 +49,10 @@ export class Store< } setState = (updater: TUpdater) => { - const prevVal = this.state + this.prevState = this.state this.state = this.options?.updateFn - ? this.options.updateFn(prevVal)(updater) - : (updater as any)(prevVal) + ? this.options.updateFn(this.prevState)(updater) + : (updater as any)(this.prevState) // Always run onUpdate, regardless of batching this.options?.onUpdate?.() From 4a0caf6e97b1626ee2ce87dfc0ad9260057cb845 Mon Sep 17 00:00:00 2001 From: Corbin Crutchley Date: Mon, 2 Dec 2024 04:18:21 -0800 Subject: [PATCH 3/8] fix: issues with recomputing should now be resolved --- packages/store/src/derived.ts | 46 +++++++++++++++++++------- packages/store/tests/derived.test.ts | 48 ++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/packages/store/src/derived.ts b/packages/store/src/derived.ts index be67a2e..7c1a368 100644 --- a/packages/store/src/derived.ts +++ b/packages/store/src/derived.ts @@ -1,6 +1,6 @@ -import { Store } from './store' -import { __derivedToStore, __storeToDerived } from './scheduler' -import type { Listener } from './types' +import {Store} from './store' +import {__derivedToStore, __storeToDerived} from './scheduler' +import type {Listener} from './types' export type UnwrapDerivedOrStore = T extends Derived @@ -22,8 +22,7 @@ type UnwrapReadonlyDerivedOrStoreArray< // Can't have currVal, as it's being evaluated from the current derived fn export interface DerivedFnProps< TArr extends ReadonlyArray | Store> = ReadonlyArray, - TUnwrappedArr extends - UnwrapReadonlyDerivedOrStoreArray = UnwrapReadonlyDerivedOrStoreArray, + TUnwrappedArr extends UnwrapReadonlyDerivedOrStoreArray = UnwrapReadonlyDerivedOrStoreArray, > { // `undefined` if it's the first run /** @@ -68,6 +67,7 @@ export class Derived< */ _subscriptions: Array<() => void> = [] + lastSeenDepValues: Array = [] getDepVals = () => { const prevDepVals = [] as Array const currDepVals = [] as Array @@ -75,9 +75,10 @@ export class Derived< prevDepVals.push(dep.prevState) currDepVals.push(dep.state) } + this.lastSeenDepValues = currDepVals return { - prevDepVals: prevDepVals as never, - currDepVals: currDepVals as never, + prevDepVals, + currDepVals, prevVal: this.prevState ?? undefined, } } @@ -87,7 +88,7 @@ export class Derived< this.state = options.fn({ prevDepVals: undefined, prevVal: undefined, - currDepVals: this.getDepVals().currDepVals, + currDepVals: this.getDepVals().currDepVals as never, }) } @@ -142,19 +143,40 @@ export class Derived< recompute = () => { this.prevState = this.state - const { prevDepVals, currDepVals, prevVal } = this.getDepVals() + const {prevDepVals, currDepVals, prevVal} = this.getDepVals() this.state = this.options.fn({ - prevDepVals, - currDepVals, + prevDepVals: prevDepVals as never, + currDepVals: currDepVals as never, prevVal, }) - // Always run onUpdate, regardless of batching this.options.onUpdate?.() } + checkIfRecalculationNeededDeeply = () => { + for (const dep of this.options.deps) { + if (dep instanceof Derived) { + dep.checkIfRecalculationNeededDeeply() + } + } + let shouldRecompute = false; + const lastSeenDepValues = this.lastSeenDepValues + const {currDepVals} = this.getDepVals() + for (let i = 0; i < currDepVals.length; i++) { + if (currDepVals[i] !== lastSeenDepValues[i]) { + shouldRecompute = true + break + } + } + + if (shouldRecompute) { + this.recompute() + } + } + mount = () => { this.registerOnGraph() + this.checkIfRecalculationNeededDeeply(); return () => { this.unregisterFromGraph() diff --git a/packages/store/tests/derived.test.ts b/packages/store/tests/derived.test.ts index 25f8de1..2326683 100644 --- a/packages/store/tests/derived.test.ts +++ b/packages/store/tests/derived.test.ts @@ -234,8 +234,6 @@ describe('Derived', () => { }, }) - count.setState(() => 24) - const cleanup1 = derived.mount() cleanup1() const cleanup2 = derived.mount() @@ -244,10 +242,56 @@ describe('Derived', () => { cleanup3() derived.mount() + count.setState(() => 24) + expect(count.state).toBe(24) expect(derived.state).toBe(48) }) + test('should handle calculating state before the derived state is mounted', () => { + const count = new Store(12) + const derived = new Derived({ + deps: [count], + fn: () => { + return count.state * 2 + }, + }) + + count.setState(() => 24) + + derived.mount() + + expect(count.state).toBe(24) + expect(derived.state).toBe(48) + }) + + test('should not recompute more than is needed', () => { + const fn = vi.fn(); + const count = new Store(12) + const derived = new Derived({ + deps: [count], + fn: () => { + fn("derived"); + return count.state * 2 + }, + }) + + count.setState(() => 24) + + const unmount1 = derived.mount() + unmount1(); + const unmount2 = derived.mount() + unmount2(); + const unmount3 = derived.mount() + unmount3(); + derived.mount() + + expect(count.state).toBe(24) + expect(derived.state).toBe(48) + expect(fn).toBeCalledTimes(2); + }) + + test('should be able to mount in the wrong order and still work', () => { const count = new Store(12) From 7a66f8d1ac406428fc17ee223a302f39865055b0 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 12:20:25 +0000 Subject: [PATCH 4/8] ci: apply automated fixes and generate docs --- docs/reference/classes/derived.md | 84 +++++++++++-------- docs/reference/functions/batch.md | 2 +- docs/reference/index.md | 1 - .../interfaces/derivedmountoptions.md | 26 ------ packages/store/src/derived.ts | 17 ++-- packages/store/tests/derived.test.ts | 13 ++- 6 files changed, 63 insertions(+), 80 deletions(-) delete mode 100644 docs/reference/interfaces/derivedmountoptions.md diff --git a/docs/reference/classes/derived.md b/docs/reference/classes/derived.md index df06f13..d94c137 100644 --- a/docs/reference/classes/derived.md +++ b/docs/reference/classes/derived.md @@ -29,71 +29,85 @@ new Derived(options): Derived #### Defined in -[derived.ts:95](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L95) +[derived.ts:87](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L87) ## Properties -### options +### lastSeenDepValues ```ts -options: DerivedOptions; +lastSeenDepValues: unknown[] = []; ``` #### Defined in -[derived.ts:72](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L72) +[derived.ts:71](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L71) -## Accessors - -### prevState +*** -#### Get Signature +### listeners ```ts -get prevState(): TState +listeners: Set>; ``` -##### Returns +#### Defined in -`TState` +[derived.ts:60](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L60) -#### Set Signature +*** + +### options ```ts -set prevState(val): void +options: DerivedOptions; ``` -##### Parameters +#### Defined in -• **val**: `TState` +[derived.ts:63](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L63) -##### Returns +*** -`void` +### prevState + +```ts +prevState: undefined | TState; +``` #### Defined in -[derived.ts:117](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L117) +[derived.ts:62](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L62) *** ### state -#### Get Signature +```ts +state: TState; +``` + +#### Defined in + +[derived.ts:61](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L61) + +## Methods + +### checkIfRecalculationNeededDeeply() ```ts -get state(): TState +checkIfRecalculationNeededDeeply(): void ``` -##### Returns +#### Returns -`TState` +`void` #### Defined in -[derived.ts:109](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L109) +[derived.ts:157](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L157) -## Methods +*** ### getDepVals() @@ -108,13 +122,13 @@ getDepVals(): object ##### currDepVals ```ts -currDepVals: never; +currDepVals: unknown[]; ``` ##### prevDepVals ```ts -prevDepVals: never; +prevDepVals: unknown[]; ``` ##### prevVal @@ -125,20 +139,16 @@ prevVal: undefined | NonNullable; #### Defined in -[derived.ts:80](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L80) +[derived.ts:72](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L72) *** ### mount() ```ts -mount(__namedParameters): () => void +mount(): () => void ``` -#### Parameters - -• **\_\_namedParameters**: [`DerivedMountOptions`](../interfaces/derivedmountoptions.md) = `{}` - #### Returns `Function` @@ -149,7 +159,7 @@ mount(__namedParameters): () => void #### Defined in -[derived.ts:181](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L181) +[derived.ts:178](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L178) *** @@ -165,7 +175,7 @@ recompute(): void #### Defined in -[derived.ts:170](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L170) +[derived.ts:145](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L145) *** @@ -185,7 +195,7 @@ registerOnGraph(deps): void #### Defined in -[derived.ts:121](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L121) +[derived.ts:96](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L96) *** @@ -209,7 +219,7 @@ subscribe(listener): () => void #### Defined in -[derived.ts:195](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L195) +[derived.ts:190](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L190) *** @@ -229,4 +239,4 @@ unregisterFromGraph(deps): void #### Defined in -[derived.ts:150](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L150) +[derived.ts:125](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L125) diff --git a/docs/reference/functions/batch.md b/docs/reference/functions/batch.md index b0e506f..36bfffd 100644 --- a/docs/reference/functions/batch.md +++ b/docs/reference/functions/batch.md @@ -19,4 +19,4 @@ function batch(fn): void ## Defined in -[scheduler.ts:100](https://github.com/TanStack/store/blob/main/packages/store/src/scheduler.ts#L100) +[scheduler.ts:120](https://github.com/TanStack/store/blob/main/packages/store/src/scheduler.ts#L120) diff --git a/docs/reference/index.md b/docs/reference/index.md index a7aba24..720551c 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -14,7 +14,6 @@ title: "@tanstack/store" ## Interfaces - [DerivedFnProps](interfaces/derivedfnprops.md) -- [DerivedMountOptions](interfaces/derivedmountoptions.md) - [DerivedOptions](interfaces/derivedoptions.md) - [StoreOptions](interfaces/storeoptions.md) diff --git a/docs/reference/interfaces/derivedmountoptions.md b/docs/reference/interfaces/derivedmountoptions.md deleted file mode 100644 index d74704b..0000000 --- a/docs/reference/interfaces/derivedmountoptions.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -id: DerivedMountOptions -title: DerivedMountOptions ---- - -# Interface: DerivedMountOptions - -## Properties - -### recompute? - -```ts -optional recompute: boolean; -``` - -Should recompute the value on mount? - -#### Default - -```ts -{true} -``` - -#### Defined in - -[derived.ts:59](https://github.com/TanStack/store/blob/main/packages/store/src/derived.ts#L59) diff --git a/packages/store/src/derived.ts b/packages/store/src/derived.ts index 7c1a368..07b2542 100644 --- a/packages/store/src/derived.ts +++ b/packages/store/src/derived.ts @@ -1,6 +1,6 @@ -import {Store} from './store' -import {__derivedToStore, __storeToDerived} from './scheduler' -import type {Listener} from './types' +import { Store } from './store' +import { __derivedToStore, __storeToDerived } from './scheduler' +import type { Listener } from './types' export type UnwrapDerivedOrStore = T extends Derived @@ -22,7 +22,8 @@ type UnwrapReadonlyDerivedOrStoreArray< // Can't have currVal, as it's being evaluated from the current derived fn export interface DerivedFnProps< TArr extends ReadonlyArray | Store> = ReadonlyArray, - TUnwrappedArr extends UnwrapReadonlyDerivedOrStoreArray = UnwrapReadonlyDerivedOrStoreArray, + TUnwrappedArr extends + UnwrapReadonlyDerivedOrStoreArray = UnwrapReadonlyDerivedOrStoreArray, > { // `undefined` if it's the first run /** @@ -143,7 +144,7 @@ export class Derived< recompute = () => { this.prevState = this.state - const {prevDepVals, currDepVals, prevVal} = this.getDepVals() + const { prevDepVals, currDepVals, prevVal } = this.getDepVals() this.state = this.options.fn({ prevDepVals: prevDepVals as never, currDepVals: currDepVals as never, @@ -159,9 +160,9 @@ export class Derived< dep.checkIfRecalculationNeededDeeply() } } - let shouldRecompute = false; + let shouldRecompute = false const lastSeenDepValues = this.lastSeenDepValues - const {currDepVals} = this.getDepVals() + const { currDepVals } = this.getDepVals() for (let i = 0; i < currDepVals.length; i++) { if (currDepVals[i] !== lastSeenDepValues[i]) { shouldRecompute = true @@ -176,7 +177,7 @@ export class Derived< mount = () => { this.registerOnGraph() - this.checkIfRecalculationNeededDeeply(); + this.checkIfRecalculationNeededDeeply() return () => { this.unregisterFromGraph() diff --git a/packages/store/tests/derived.test.ts b/packages/store/tests/derived.test.ts index 2326683..127afbc 100644 --- a/packages/store/tests/derived.test.ts +++ b/packages/store/tests/derived.test.ts @@ -266,12 +266,12 @@ describe('Derived', () => { }) test('should not recompute more than is needed', () => { - const fn = vi.fn(); + const fn = vi.fn() const count = new Store(12) const derived = new Derived({ deps: [count], fn: () => { - fn("derived"); + fn('derived') return count.state * 2 }, }) @@ -279,19 +279,18 @@ describe('Derived', () => { count.setState(() => 24) const unmount1 = derived.mount() - unmount1(); + unmount1() const unmount2 = derived.mount() - unmount2(); + unmount2() const unmount3 = derived.mount() - unmount3(); + unmount3() derived.mount() expect(count.state).toBe(24) expect(derived.state).toBe(48) - expect(fn).toBeCalledTimes(2); + expect(fn).toBeCalledTimes(2) }) - test('should be able to mount in the wrong order and still work', () => { const count = new Store(12) From 632ba17a06407d9bd84a2ab9fceea975dd149cfa Mon Sep 17 00:00:00 2001 From: Corbin Crutchley Date: Mon, 2 Dec 2024 06:21:25 -0800 Subject: [PATCH 5/8] chore: add failing test --- packages/store/tests/derived.test.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/store/tests/derived.test.ts b/packages/store/tests/derived.test.ts index 127afbc..1b93f71 100644 --- a/packages/store/tests/derived.test.ts +++ b/packages/store/tests/derived.test.ts @@ -318,6 +318,34 @@ describe('Derived', () => { expect(halfDouble.state).toBe(24) }) + + test('should be able to mount in the wrong order and still work with a derived and a non-derived state', () => { + const count = new Store(12) + + const double = new Derived({ + deps: [count], + fn: () => { + return count.state * 2 + }, + }) + + const countPlusDouble = new Derived({ + deps: [count, double], + fn: () => { + return count.state + double.state + }, + }) + + countPlusDouble.mount() + double.mount() + + count.setState(() => 24) + + expect(count.state).toBe(24) + expect(double.state).toBe(48) + expect(countPlusDouble.state).toBe(24 + 48) + }) + test('should recompute in the right order', () => { const count = new Store(12) From babe78050704e0fbcfed21d65aa7cdc31beb3e11 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:22:20 +0000 Subject: [PATCH 6/8] ci: apply automated fixes and generate docs --- packages/store/tests/derived.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/store/tests/derived.test.ts b/packages/store/tests/derived.test.ts index 1b93f71..df806d6 100644 --- a/packages/store/tests/derived.test.ts +++ b/packages/store/tests/derived.test.ts @@ -318,7 +318,6 @@ describe('Derived', () => { expect(halfDouble.state).toBe(24) }) - test('should be able to mount in the wrong order and still work with a derived and a non-derived state', () => { const count = new Store(12) From aada7c7387d7f0764d0eae5dfbab23c8463cf409 Mon Sep 17 00:00:00 2001 From: Corbin Crutchley Date: Mon, 2 Dec 2024 06:34:22 -0800 Subject: [PATCH 7/8] fix: add fix to broken test --- packages/store/src/scheduler.ts | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/store/src/scheduler.ts b/packages/store/src/scheduler.ts index 0e05e0e..87eb19a 100644 --- a/packages/store/src/scheduler.ts +++ b/packages/store/src/scheduler.ts @@ -1,5 +1,5 @@ +import { Derived } from './derived' import type { Store } from './store' -import type { Derived } from './derived' /** * This is here to solve the pyramid dependency problem where: @@ -34,20 +34,29 @@ let __batchDepth = 0 const __pendingUpdates = new Set>() function __flush_internals(relatedVals: Set>) { - for (const derived of relatedVals) { + // First sort deriveds by dependency order + const sorted = Array.from(relatedVals).sort((a, b) => { + // If a depends on b, b should go first + if (a instanceof Derived && a.options.deps.includes(b)) return 1; + // If b depends on a, a should go first + if (b instanceof Derived && b.options.deps.includes(a)) return -1; + return 0; + }); + + for (const derived of sorted) { if (__depsThatHaveWrittenThisTick.current.includes(derived)) { - continue + continue; } - __depsThatHaveWrittenThisTick.current.push(derived) - derived.recompute() + __depsThatHaveWrittenThisTick.current.push(derived); + derived.recompute(); - const stores = __derivedToStore.get(derived) + const stores = __derivedToStore.get(derived); if (stores) { for (const store of stores) { - const relatedLinkedDerivedVals = __storeToDerived.get(store) - if (!relatedLinkedDerivedVals) continue - __flush_internals(relatedLinkedDerivedVals) + const relatedLinkedDerivedVals = __storeToDerived.get(store); + if (!relatedLinkedDerivedVals) continue; + __flush_internals(relatedLinkedDerivedVals); } } } From 4c9fe4d946b2321e98c7787abe0337d8e98e6cfe Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:35:17 +0000 Subject: [PATCH 8/8] ci: apply automated fixes and generate docs --- docs/reference/functions/batch.md | 2 +- packages/store/src/scheduler.ts | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/reference/functions/batch.md b/docs/reference/functions/batch.md index 36bfffd..c5be233 100644 --- a/docs/reference/functions/batch.md +++ b/docs/reference/functions/batch.md @@ -19,4 +19,4 @@ function batch(fn): void ## Defined in -[scheduler.ts:120](https://github.com/TanStack/store/blob/main/packages/store/src/scheduler.ts#L120) +[scheduler.ts:129](https://github.com/TanStack/store/blob/main/packages/store/src/scheduler.ts#L129) diff --git a/packages/store/src/scheduler.ts b/packages/store/src/scheduler.ts index 87eb19a..2834d0d 100644 --- a/packages/store/src/scheduler.ts +++ b/packages/store/src/scheduler.ts @@ -37,26 +37,26 @@ function __flush_internals(relatedVals: Set>) { // First sort deriveds by dependency order const sorted = Array.from(relatedVals).sort((a, b) => { // If a depends on b, b should go first - if (a instanceof Derived && a.options.deps.includes(b)) return 1; + if (a instanceof Derived && a.options.deps.includes(b)) return 1 // If b depends on a, a should go first - if (b instanceof Derived && b.options.deps.includes(a)) return -1; - return 0; - }); + if (b instanceof Derived && b.options.deps.includes(a)) return -1 + return 0 + }) for (const derived of sorted) { if (__depsThatHaveWrittenThisTick.current.includes(derived)) { - continue; + continue } - __depsThatHaveWrittenThisTick.current.push(derived); - derived.recompute(); + __depsThatHaveWrittenThisTick.current.push(derived) + derived.recompute() - const stores = __derivedToStore.get(derived); + const stores = __derivedToStore.get(derived) if (stores) { for (const store of stores) { - const relatedLinkedDerivedVals = __storeToDerived.get(store); - if (!relatedLinkedDerivedVals) continue; - __flush_internals(relatedLinkedDerivedVals); + const relatedLinkedDerivedVals = __storeToDerived.get(store) + if (!relatedLinkedDerivedVals) continue + __flush_internals(relatedLinkedDerivedVals) } } }