+
Skip to content

feat(store): implement ActionDirector #2329

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 16, 2025
Merged

feat(store): implement ActionDirector #2329

merged 1 commit into from
Jun 16, 2025

Conversation

arturovt
Copy link
Member

@arturovt arturovt commented May 13, 2025

The ActionDirector allows you to attach action handlers to a state at any point after
initialization and gives you the ability to detach them when no longer needed.

@arturovt arturovt force-pushed the feat/attach-action branch from 0239ed1 to 86e0f6c Compare May 13, 2025 17:20
markwhitfeld

This comment was marked as outdated.

@joaqcid

This comment was marked as outdated.

@markwhitfeld

This comment was marked as outdated.

@ngxs ngxs deleted a comment from bundlemon bot May 17, 2025
@ngxs ngxs deleted a comment from bundlemon bot May 17, 2025
@ngxs ngxs deleted a comment from bundlemon bot May 17, 2025
@ngxs ngxs deleted a comment from codeclimate bot May 17, 2025
@ngxs ngxs deleted a comment from pkg-pr-new bot May 17, 2025
@ngxs ngxs deleted a comment from nx-cloud bot May 17, 2025
@arturovt arturovt force-pushed the feat/attach-action branch from 00eca4e to 3d2d0a0 Compare May 18, 2025 22:04
@ngxs ngxs deleted a comment from bundlemon bot May 25, 2025
@ngxs ngxs deleted a comment from bundlemon bot May 25, 2025
@ngxs ngxs deleted a comment from bundlemon bot May 25, 2025
@ngxs ngxs deleted a comment from pkg-pr-new bot May 25, 2025
@ngxs ngxs deleted a comment from nx-cloud bot May 25, 2025
@arturovt arturovt force-pushed the feat/attach-action branch from 3d2d0a0 to 25deb53 Compare May 25, 2025 13:27
@ngxs ngxs deleted a comment from pkg-pr-new bot May 25, 2025
@ngxs ngxs deleted a comment from nx-cloud bot May 25, 2025
Copy link
Member

@markwhitfeld markwhitfeld left a comment

Choose a reason for hiding this comment

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

Thank you so much for trying this out, but I'm not a fan of this approach.
It doesn't solve the complexity around injection context. And the queue seems a bit arbitrary. My thought along these lines was that we would be queueing the action handlers on a static queue, so that attachAction can be called independant of an injection context.

I think that I am solidly leaning away from the "magic" 'call from anywhere' function, and towards the more explicit call to a member of a service.

I'll unpack my thoughts in the next comment on this PR...

@markwhitfeld
Copy link
Member

I think that the following API would make things much simpler and more explicit:

const actionDirector = inject(ActionDirector);
// somewhere appropriate in the code
actionDirector.attachAction(
  CountriesState, 
  AddCountry, 
  (ctx: StateContext<string[]>, action: AddCountry) => {
    ctx.setState(countries => [...countries, action.country]);
  }
);

and to build on this example with more a complex usage and side effects:

const actionDirector = inject(ActionDirector);
const countryRepo = inject(CountryRepo);
// somewhere appropriate in the code
const detachMe = actionDirector.attachAction(
  CountriesState, 
  AddCountry, 
  async (ctx: StateContext<string[]>, action: AddCountry) => {
    // Note: this is not run inside an injection context, just like in the states
    ctx.setState(countries => [...countries, action.country]);
    await countryRepo.Add(action.country);
  }
);
const destroyRef = inject(DestroyRef);
destroyRef.onDestroy(() => detachMe());

We could also provide another function (effect) that is only for side effects that don't influence state:

const actionDirector = inject(ActionDirector);
const countryRepo = inject(CountryRepo);
// somewhere appropriate in the code
const stopEffect = actionDirector.effect(
  AddCountry, 
  async (action: AddCountry) => {
    // Note: this is not run inside an injection context, just like in the states
    await countryRepo.Add(action.country);
  }
);
const destroyRef = inject(DestroyRef);
destroyRef.onDestroy(() => stopEffect());

With respect to the naming of these functions, I have thought of a few options:

  1. attachAction, effect
  2. onAction, effect
  3. reaction, effect

What do you think?

@arturovt

This comment was marked as outdated.

@markwhitfeld

This comment was marked as outdated.

@arturovt

This comment was marked as outdated.

@arturovt arturovt force-pushed the feat/attach-action branch from 25deb53 to fb0bf6b Compare May 30, 2025 08:11
@ngxs ngxs deleted a comment from pkg-pr-new bot May 30, 2025
@ngxs ngxs deleted a comment from codeclimate bot May 30, 2025
@markwhitfeld
Copy link
Member

Good points. I think I'm leaning towards attachAction because it gives the conceptual model of an action that is connected to a state, and therefore can update that state. effect is for side effects, and has nothing to do with a state, so that name is good.

I also think that the signature for the function should require the state model type information (to be able to provide to the StateContext), and, with that in mind, maybe requiring a StateToken as opposed to a state class as the first parameter would push towards the more type safe API.

@arturovt arturovt force-pushed the feat/attach-action branch from fb0bf6b to b896ec2 Compare June 1, 2025 22:39
@profanis
Copy link
Contributor

profanis commented Jun 6, 2025

I have made some changes and added documentation for this feature.
@joaqcid and @profanis please could you have a read through the docs I created for this and give me your feedback?

The explanation is easy to follow 💯


- Add action handlers conditionally based on runtime conditions
- Add action handlers for lazy-loaded modules
- Add temporary action handlers that can be removed later
Copy link
Contributor

Choose a reason for hiding this comment

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

  • Add action handler to fine-grain control when an action is completed


- It gives you the ability to make changes to state from your handler
- It participates in the standard [actions life cycle](./actions-life-cycle.md)
- The result of the handler will affect the completion result of the action
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe add an example?

(i.e. if the action handler is async, dispatched action will be "COMPLETED" once it finishes)

@joaqcid
Copy link
Contributor

joaqcid commented Jun 11, 2025

I have made some changes and added documentation for this feature. @joaqcid and @profanis please could you have a read through the docs I created for this and give me your feedback?

i added a couple of comments, but overall looks great!

thanks!!

@arturovt arturovt force-pushed the feat/attach-action branch from efb9939 to 6922684 Compare June 16, 2025 08:20
@ngxs ngxs deleted a comment from codeclimate bot Jun 16, 2025
@ngxs ngxs deleted a comment from bundlemon bot Jun 16, 2025
@ngxs ngxs deleted a comment from bundlemon bot Jun 16, 2025
@ngxs ngxs deleted a comment from bundlemon bot Jun 16, 2025
@ngxs ngxs deleted a comment from pkg-pr-new bot Jun 16, 2025
@ngxs ngxs deleted a comment from nx-cloud bot Jun 16, 2025
@arturovt arturovt force-pushed the feat/attach-action branch from 6922684 to 8df1b09 Compare June 16, 2025 10:10
@arturovt arturovt changed the title feat(store): implement attachAction feat(store): implement ActionDirector Jun 16, 2025
The `ActionDirector` allows you to attach action handlers to a state at any point after
initialization and gives you the ability to detach them when no longer needed.
@arturovt arturovt force-pushed the feat/attach-action branch from 8df1b09 to d8e1bf5 Compare June 16, 2025 10:12
@ngxs ngxs deleted a comment from pkg-pr-new bot Jun 16, 2025
@ngxs ngxs deleted a comment from nx-cloud bot Jun 16, 2025
@ngxs ngxs deleted a comment from codeclimate bot Jun 16, 2025
@ngxs ngxs deleted a comment from bundlemon bot Jun 16, 2025
@ngxs ngxs deleted a comment from bundlemon bot Jun 16, 2025
@ngxs ngxs deleted a comment from bundlemon bot Jun 16, 2025
@ngxs ngxs deleted a comment from pkg-pr-new bot Jun 16, 2025
@ngxs ngxs deleted a comment from nx-cloud bot Jun 16, 2025
@arturovt arturovt merged commit c739a26 into master Jun 16, 2025
14 of 15 checks passed
@arturovt arturovt deleted the feat/attach-action branch June 16, 2025 10:21
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.

4 participants
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载