Skip to content

Commit 741d30d

Browse files
fix(devtools): fix event tracker
1 parent 06fb7c8 commit 741d30d

3 files changed

Lines changed: 55 additions & 30 deletions

File tree

libs/ngrx-toolkit/src/lib/devtools/tests/with-tracked-reducer.spec.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
eventGroup,
1414
Events,
1515
on,
16-
withEventHandlers,
16+
withEffects,
1717
} from '@ngrx/signals/events';
1818
import { delay, tap } from 'rxjs';
1919
import { withDisabledNameIndices } from '../features/with-disabled-name-indicies';
@@ -137,15 +137,15 @@ describe('withTrackedReducer', () => {
137137
{ providedIn: 'root' },
138138
withBasicStore('store'),
139139
withState({ count: 0 }),
140-
withEventHandlers((store, events = inject(Events)) => [
141-
events
140+
withEffects((store, events = inject(Events)) => ({
141+
bump$: events
142142
.on(testEvents.bump)
143143
.pipe(
144144
tap(() =>
145145
patchState(store, (state) => ({ count: state.count + 1 })),
146146
),
147147
),
148-
]),
148+
})),
149149
);
150150

151151
TestBed.inject(Store);
@@ -163,12 +163,12 @@ describe('withTrackedReducer', () => {
163163
const Store = signalStore(
164164
{ providedIn: 'root' },
165165
withBasicStore('store'),
166-
withEventHandlers((store, events = inject(Events)) => [
167-
events.on(testEvents.bump).pipe(
166+
withEffects((store, events = inject(Events)) => ({
167+
bump$: events.on(testEvents.bump).pipe(
168168
delay(0),
169169
tap(() => patchState(store, (state) => ({ count: state.count + 1 }))),
170170
),
171-
]),
171+
})),
172172
);
173173

174174
TestBed.inject(Store);
@@ -187,11 +187,11 @@ describe('withTrackedReducer', () => {
187187
const Store = signalStore(
188188
{ providedIn: 'root' },
189189
withBasicStore('store'),
190-
withEventHandlers((store, events = inject(Events)) => [
191-
events
190+
withEffects((store, events = inject(Events)) => ({
191+
bump$: events
192192
.on(testEvents.bump)
193193
.pipe(tap(() => updateState(store, 'Bump', { count: 1 }))),
194-
]),
194+
})),
195195
);
196196

197197
TestBed.inject(Store);

libs/ngrx-toolkit/src/lib/devtools/with-tracked-reducer.ts

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { inject, untracked } from '@angular/core';
2+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
23
import {
34
EmptyFeatureResult,
45
getState,
@@ -8,12 +9,8 @@ import {
89
type,
910
withHooks,
1011
} from '@ngrx/signals';
11-
import {
12-
EventCreator,
13-
ReducerEvents,
14-
withEventHandlers,
15-
} from '@ngrx/signals/events';
16-
import { tap } from 'rxjs/operators';
12+
import { Dispatcher, EventCreator } from '@ngrx/signals/events';
13+
import { merge, tap } from 'rxjs';
1714
import { GLITCH_TRACKING_FEATURE } from './features/with-glitch-tracking';
1815
import { updateState } from './update-state';
1916
import { DEVTOOL_FEATURE_NAMES } from './with-devtools';
@@ -31,19 +28,6 @@ export function withTrackedReducer<State extends object>(
3128
{
3229
state: type<State>(),
3330
},
34-
withEventHandlers((store, events = inject(ReducerEvents)) =>
35-
caseReducers.map((caseReducer) =>
36-
events.on(...caseReducer.events).pipe(
37-
tap((event) => {
38-
const state = untracked(() => getState(store));
39-
const result = caseReducer.reducer(event, state);
40-
const updaters = Array.isArray(result) ? result : [result];
41-
42-
updateState(store, event.type, ...updaters);
43-
}),
44-
),
45-
),
46-
),
4731
withHooks((store) => ({
4832
onInit() {
4933
if (!(DEVTOOL_FEATURE_NAMES in store)) {
@@ -60,6 +44,23 @@ export function withTrackedReducer<State extends object>(
6044
`In order to use withTrackedReducer, you must first enable the glitch tracking devtools feature via withDevtools('[your store name]', withGlitchTracking())`,
6145
);
6246
}
47+
48+
const events = getReducerEvents();
49+
const updates = caseReducers.map((caseReducer) =>
50+
events.on(...caseReducer.events).pipe(
51+
tap((event) => {
52+
const state = untracked(() => getState(store));
53+
const result = caseReducer.reducer(event, state);
54+
const updaters = Array.isArray(result) ? result : [result];
55+
56+
updateState(store, event.type, ...updaters);
57+
}),
58+
),
59+
);
60+
61+
merge(...updates)
62+
.pipe(takeUntilDestroyed())
63+
.subscribe();
6364
},
6465
})),
6566
);
@@ -82,3 +83,27 @@ type CaseReducer<
8283
| Partial<State>
8384
| PartialStateUpdater<State>
8485
| Array<Partial<State> | PartialStateUpdater<State>>;
86+
87+
/**
88+
* Returns the synchronous reducer event stream exposed by the dispatcher.
89+
*
90+
* NgRx's `Dispatcher` delivers events to `ReducerEvents` immediately but feeds
91+
* the public `Events` stream via `queueScheduler`, which keeps work in a FIFO
92+
* queue and executes scheduled tasks only after the current task completes
93+
* ([rxjs.dev](https://rxjs.dev/api/index/const/queueScheduler)). When
94+
* `GlitchTrackerService` captures the state change synchronously, that queued
95+
* `Events` emission is processed afterward and DevTools records the update as
96+
* `Store Update`. Tapping into the reducer stream keeps event names and state
97+
* changes aligned.
98+
*
99+
* TODO(@ngrx): expose a synchronous events API (similar to what `withReducer` uses)
100+
* so consumers do not need to reach into dispatcher internals.
101+
*/
102+
function getReducerEvents() {
103+
type ReducerEventsLike = Dispatcher['reducerEvents'];
104+
105+
const dispatcher = inject(Dispatcher) as unknown as {
106+
reducerEvents: ReducerEventsLike;
107+
};
108+
return dispatcher.reducerEvents;
109+
}

libs/ngrx-toolkit/src/lib/with-resource/tests/util/fixtures.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ export const vienna: Address = {
3131
export class AddressResolver {
3232
resolve(id: number) {
3333
void id;
34-
return Promise.resolve<Address>(this.address);
34+
return Promise.resolve<Address>(venice);
3535
}
3636
}

0 commit comments

Comments
 (0)