RFC: Expose Event Payload in Redux DevTools via withTrackedReducer
1. Summary
When using withTrackedReducer, the Redux DevTools extension currently logs only the string name of a dispatched event (e.g., [User] Update Age). The associated payload is silently discarded, leaving developers without visibility into what data drove a state transition.
This RFC proposes three coordinated, non-breaking internal changes to surface the full event object — including its payload — in the DevTools action log:
- Refactor
withTrackedReducer to forward the full event object instead of extracting only event.type.
- Add an overload to the internal
updateState utility that accepts an EventInstance (any object with a type: string property) as its action descriptor.
- Update
DevtoolsSyncer to pass that full object to the Redux DevTools extension, making payload data visible alongside the action type.
2. Motivation
2.1 Developer Experience Gap
NgRx Signal Store's withTrackedReducer is designed to bring reducer-style determinism to the Signal Store. However, the current DevTools integration surfaces only half of the picture: the name of what happened, but not what happened. In practice, this forces developers to fall back to console.log statements inside their reducers to inspect the payload driving each transition — exactly the kind of manual introspection that DevTools is meant to eliminate.
2.2 Parity with Traditional NgRx
In a classic NgRx Store setup backed by @ngrx/store-devtools, every dispatched action appears in the DevTools panel with its full serialized payload. A developer can click any entry in the action log and immediately inspect the data. withTrackedReducer should provide the same level of observability; the current behaviour is a silent regression in DX for teams migrating from, or running alongside, the traditional NgRx store.
3. Design
3.1 — withTrackedReducer: pass the full event, not just the type
// Before
updateState(store, event.type, nextState);
// After
updateState(store, event, nextState);
3.2 — updateState: add an object overload
// Existing overload — unchanged
export function updateState<State extends object>(
stateSource: WritableStateSource<State>,
action: string,
...updaters: Array<
Partial<NoInfer<State>> | PartialStateUpdater<NoInfer<State>>
>
): void;
// New overload
export function updateState<State extends object>(
stateSource: WritableStateSource<State>,
eventInstance: EventInstance<string, any>,
...updaters: Array<
Partial<NoInfer<State>> | PartialStateUpdater<NoInfer<State>>
>
): void;
// Implementation normalises both shapes
export function updateState<State extends object>(
stateSource: WritableStateSource<State>,
eventOrEventType: string | EventInstance<string, any>,
...updaters: Array<
Partial<NoInfer<State>> | PartialStateUpdater<NoInfer<State>>
>
): void {
if (typeof eventOrEventType === 'string') {
currentActionNames.add(eventOrEventType);
} else {
currentEvents.add(eventOrEventType);
}
return originalPatchState(stateSource, ...updaters);
}
3.3 — DevtoolsSyncer: forward the object to the extension
// Before
this.#connection.send({ type }, this.#currentState);
// After — Redux DevTools natively supports action objects
this.#connection.send({ type, payload }, this.#currentState);
Result in DevTools:
// Before
▶ [User] Update Age
type: "[User] Update Age"
// After
▶ [User] Update Age
type: "[User] Update Age"
payload: {
userId: "u_4821"
age: 31
}
4. Adoption Strategy
Strictly non-breaking. The string overload is preserved. No consumer code changes. No migration guide needed. Safe to ship as a minor release.
5. Implementation Plan
I have a working local fork with all three changes verified against the Chrome DevTools extension. The PR will include unit tests for both updateState overloads and E2E verification that the payload appears correctly in the action log.
RFC: Expose Event Payload in Redux DevTools via
withTrackedReducer1. Summary
When using
withTrackedReducer, the Redux DevTools extension currently logs only the string name of a dispatched event (e.g.,[User] Update Age). The associated payload is silently discarded, leaving developers without visibility into what data drove a state transition.This RFC proposes three coordinated, non-breaking internal changes to surface the full event object — including its payload — in the DevTools action log:
withTrackedReducerto forward the full event object instead of extracting onlyevent.type.updateStateutility that accepts anEventInstance(any object with atype: stringproperty) as its action descriptor.DevtoolsSyncerto pass that full object to the Redux DevTools extension, making payload data visible alongside the action type.2. Motivation
2.1 Developer Experience Gap
NgRx Signal Store's
withTrackedReduceris designed to bring reducer-style determinism to the Signal Store. However, the current DevTools integration surfaces only half of the picture: the name of what happened, but not what happened. In practice, this forces developers to fall back toconsole.logstatements inside their reducers to inspect the payload driving each transition — exactly the kind of manual introspection that DevTools is meant to eliminate.2.2 Parity with Traditional NgRx
In a classic NgRx
Storesetup backed by@ngrx/store-devtools, every dispatched action appears in the DevTools panel with its full serialized payload. A developer can click any entry in the action log and immediately inspect the data.withTrackedReducershould provide the same level of observability; the current behaviour is a silent regression in DX for teams migrating from, or running alongside, the traditional NgRx store.3. Design
3.1 —
withTrackedReducer: pass the full event, not just the type3.2 —
updateState: add an object overload3.3 —
DevtoolsSyncer: forward the object to the extensionResult in DevTools:
4. Adoption Strategy
Strictly non-breaking. The
stringoverload is preserved. No consumer code changes. No migration guide needed. Safe to ship as a minor release.5. Implementation Plan
I have a working local fork with all three changes verified against the Chrome DevTools extension. The PR will include unit tests for both
updateStateoverloads and E2E verification that the payload appears correctly in the action log.