Skip to content

feat(devtools): expose tracked event payloads from withTrackedReducer#302

Open
sqrter wants to merge 4 commits into
angular-architects:mainfrom
sqrter:main
Open

feat(devtools): expose tracked event payloads from withTrackedReducer#302
sqrter wants to merge 4 commits into
angular-architects:mainfrom
sqrter:main

Conversation

@sqrter
Copy link
Copy Markdown

@sqrter sqrter commented May 7, 2026

withTrackedReducer now forwards full event objects to updateState so Redux DevTools can show payload data, not only action names.

Closes #294

withTrackedReducer now forwards full event objects to updateState so Redux DevTools can show payload data, not only action names.
@rainerhahnekamp
Copy link
Copy Markdown
Collaborator

rainerhahnekamp commented May 17, 2026

Please let's not start multiple PRs for the same topic. I am closing that one. If there is no progress in #295 in the next 7 days, you can continue there.

@sqrter
Copy link
Copy Markdown
Author

sqrter commented May 17, 2026

Hi @rainerhahnekamp, thanks for your response. I created it separately simply because I didn’t want to interfere with the changes that @OleksandrOleniuk made. Besides, I wasn’t sure if I understood your comments correctly. From my perspective, it would be better to continue the discussion on the newer pull request, since the old one hasn’t had any activity for a while + changing it means more work to do than just moving on with the new one.

@rainerhahnekamp
Copy link
Copy Markdown
Collaborator

@sqrter I've pinged @OleksandrOleniuk. Let's give him the 7 days

Copy link
Copy Markdown
Collaborator

@rainerhahnekamp rainerhahnekamp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, great work, just one comment.

export function updateState<State extends object>(
stateSource: WritableStateSource<State>,
action: string,
action: string | Action,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

careful, that could be a breaking change. because if someone has a state of type {type: string}, TypeScript could have an issue in detecting if this is now the action name or update.
so better to pass on type in with-tracked-reducer and keep updateState untouched.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rainerhahnekamp, thanks for the review — you're absolutely right about the breaking change risk.
I reverted updateState to action: string only, keeping the public API untouched. To still forward event payloads from withTrackedReducer, I replaced the updateState call inside the reducer with direct currentActionNames.add(event) + patchState(store, ...updaters). This way withTrackedReducer keeps showing full payloads in DevTools, but updateState stays backward compatible.

@sqrter sqrter requested a review from rainerhahnekamp May 30, 2026 22:33
const updaters = Array.isArray(result) ? result : [result];

updateState(store, event.type, ...updaters);
currentActionNames.add(event);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would really like to avoid accessing that one outside the core. are there other options?

I was thinking that we could maybe try out a branded type for action. then we could keep the action as a whole.

what do you think?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see, but I'm not sure whether a branded type wouldn't be an overkill, simply because the users who want to manually pass Action objects would need an explicit as Action cast or similar... I think we could just completely revert the changes in with-tracked-reducer.ts, and in updateState, the action type would again become action: string | Action,. If this tiny type change in the updateState is acceptable, I can do this.

Copy link
Copy Markdown
Author

@sqrter sqrter Jun 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rainerhahnekamp Looking back at the conversation, I realized that it's the point about the breaking change you mentioned earlier. As far as I undertant, the edge case is when State = { type: string } and the user would call updateState(store, {type:'someType', payload: 'somePayload'}, { type: 'bar' }), right?

So the question is, would it be fine if we:

  1. create a branded type for action, something like:
declare const __actionBrand: unique symbol;
export type Action = { type: string; [key: string]: unknown } & {
  readonly [__actionBrand]: true;
};
  1. export it from public API

The usage would be like updateState(store, { type: 'Load', id: '1' } as Action, { loading: true });

Or we could also have some helper function updateState(store, createAction('[Books] Load', { id: '1' }), { loading: true });

What do you think?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UPD: I updated the pull request to roughly see what it might look like. Still, I added a function asAction so we don't have to cast like as unknown as Action everywhere. I haven't added anything to the docs yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFC: Expose Event Payload in Redux DevTools via withTrackedReducer

2 participants