Skip to content

Commit eddedf7

Browse files
committed
refactor(angular-query): injectMutationState use signal sandwich pattern
1 parent 907087f commit eddedf7

File tree

3 files changed

+28
-52
lines changed

3 files changed

+28
-52
lines changed

.changeset/inject-is-mutating-readonly.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.changeset/tidy-parents-send.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/angular-query-experimental': patch
3+
---
4+
5+
Refactor `injectMutationState` to use signal sandwich pattern for improved consistency and maintainability

packages/angular-query-experimental/src/inject-mutation-state.ts

Lines changed: 23 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@ import {
66
computed,
77
inject,
88
signal,
9+
untracked,
910
} from '@angular/core'
10-
import {
11-
QueryClient,
12-
notifyManager,
13-
replaceEqualDeep,
14-
} from '@tanstack/query-core'
11+
import { QueryClient, replaceEqualDeep } from '@tanstack/query-core'
1512
import type { Signal } from '@angular/core'
1613
import type {
1714
Mutation,
@@ -53,12 +50,12 @@ export interface InjectMutationStateOptions {
5350

5451
/**
5552
* Injects a signal that tracks the state of all mutations.
56-
* @param injectMutationStateFn - A function that returns mutation state options.
53+
* @param mutationStateFn - A function that returns mutation state options.
5754
* @param options - The Angular injector to use.
5855
* @returns The signal that tracks the state of all mutations.
5956
*/
6057
export function injectMutationState<TResult = MutationState>(
61-
injectMutationStateFn: () => MutationStateOptions<TResult> = () => ({}),
58+
mutationStateFn: () => MutationStateOptions<TResult> = () => ({}),
6259
options?: InjectMutationStateOptions,
6360
): Signal<Array<TResult>> {
6461
!options?.injector && assertInInjectionContext(injectMutationState)
@@ -69,53 +66,32 @@ export function injectMutationState<TResult = MutationState>(
6966
const mutationCache = queryClient.getMutationCache()
7067

7168
/**
72-
* Computed signal that gets result from mutation cache based on passed options
73-
* First element is the result, second element is the time when the result was set
74-
*/
75-
const resultFromOptionsSignal = computed(() => {
76-
return [
77-
getResult(mutationCache, injectMutationStateFn()),
78-
performance.now(),
79-
] as const
80-
})
81-
82-
/**
83-
* Signal that contains result set by subscriber
84-
* First element is the result, second element is the time when the result was set
69+
* Returning a writable signal from a computed is similar to `linkedSignal`,
70+
* but compatible with Angular < 19
71+
*
72+
* Compared to `linkedSignal`, this pattern requires extra parentheses:
73+
* - Accessing value: `result()()`
74+
* - Setting value: `result().set(newValue)`
8575
*/
86-
const resultFromSubscriberSignal = signal<[Array<TResult>, number] | null>(
87-
null,
76+
const linkedStateSignal = computed(() =>
77+
signal(getResult(mutationCache, mutationStateFn())),
8878
)
8979

90-
/**
91-
* Returns the last result by either subscriber or options
92-
*/
93-
const effectiveResultSignal = computed(() => {
94-
const optionsResult = resultFromOptionsSignal()
95-
const subscriberResult = resultFromSubscriberSignal()
96-
return subscriberResult && subscriberResult[1] > optionsResult[1]
97-
? subscriberResult[0]
98-
: optionsResult[0]
99-
})
80+
const updateMutationState = () =>
81+
ngZone.run(() =>
82+
untracked(() =>
83+
linkedStateSignal().update((current) => {
84+
const next = getResult(mutationCache, mutationStateFn())
85+
return replaceEqualDeep(current, next)
86+
}),
87+
),
88+
)
10089

10190
const unsubscribe = ngZone.runOutsideAngular(() =>
102-
mutationCache.subscribe(
103-
notifyManager.batchCalls(() => {
104-
const [lastResult] = effectiveResultSignal()
105-
const nextResult = replaceEqualDeep(
106-
lastResult,
107-
getResult(mutationCache, injectMutationStateFn()),
108-
)
109-
if (lastResult !== nextResult) {
110-
ngZone.run(() => {
111-
resultFromSubscriberSignal.set([nextResult, performance.now()])
112-
})
113-
}
114-
}),
115-
),
91+
mutationCache.subscribe(updateMutationState),
11692
)
11793

11894
destroyRef.onDestroy(unsubscribe)
11995

120-
return effectiveResultSignal
96+
return computed(() => linkedStateSignal()())
12197
}

0 commit comments

Comments
 (0)