@DataAction
@DataAction() - This decorator emulates the execution of asynchronous or synchronous actions. Actions can either be thought of as a command which should trigger something to happen.
Before (origin NGXS behavior)
export class AddTodo {
public static type = '[Add todo]';
constructor(public payload: string) {}
}
@State<string[]>({
name: 'todo',
defaults: [],
})
@Injectable()
export class TodoState extends NgxsDataRepository<string[]> {
@Action(AddTodo)
public add({setState}: StateContext<string[]>, {payload}: AddTodo): void {
setState((state) => state.concat(payload));
}
}@Component({
selector: 'app',
template: `
<input #inputElement />
<button (click)="addTodo(inputElement.value)">Add todo</button>
`,
})
class AppComponent {
constructor(private store: Store) {}
public addTodo(value: string): void {
this.store.dispatch(new AddTodo(value));
}
}After (Data-plugin behavior)
The method todo.add(payload) is the same as store.dispatch({ type: '@todo.add', todo: payload }).
Also you can invoke simple setState action:
The method todo.setState(payload) is the same as store.dispatch({ type: '@todo.setState($arg0)', payload: todo }).
What are the benefits?
No need to create action classes
Typing improvements for state context
Explicit interaction with states
Don't use nested actions
Bad
Good
Bad
Good
What difference between this.ctx.setState and this.setState?
this.ctx.setState and this.setState?In order to understand the difference, you need to give some examples:
setState - this is a public method of the NgxsDataRepository class, it is annotated by the action decorator. This means that when it is called, an action will be registered into Store and will be called dispatch from Store. Thus you will see the state of the changed state through the logger or devtools plugins. When you call setState then it calls the ctx.setState method from state context.
State Context provides a way to pass data through the global states tree without having to pass new state manually at every level.
However, there is an unpleasant moment here, if you call the context directly, then you may not see anything in the devtools, because the context will be called immediately without dispatching states:
Therefore, the context should only be called inside the action.
However, there are very difficult situations in which you yourself need to determine which method should be an action and which should not:
In this situation, we have some problem:
Why didn’t we see anything? why didn’t we see a new state?

Everything is very simple, we made our method an action, this method is asynchronous and when the request ends, the action ends. But then we manually change the state directly through the context, but the previous action has already completed and we will not get the difference in states in the devtools.
We can try it differently:

Now everything works, but in this case, we understand that the getContent method should be an ordinary method, not an action, because during its execution the state does not change, the state changes only after the request is completed. Therefore, it would be more correct to write such code:

Payload
PayloadBy default, all arguments have no name when automatically creating an action.

If during logging you want to see the payload, then you need to specify which action argument is this payload, using the @Payload() decorator.

If you do not want to see the payload, but want to see the name of the arguments normally, you can use the named decorator.

Decorators can be combined:

How to check whether the code is in NgZone?
NgZone?The most common use of action is to optimize performance when starting a work consisting of one or more asynchronous or synchronous tasks that don't require UI updates or error handling to be handled by Angular. Such tasks can be kicked off via runOutsideAngular and if needed, these tasks can reenter the Angular zone via run.
By default, all action methods are called outside the Angular zone. But if you want to change this, you can define a parameter insideZone:
Use @DataAction without subscription
@DataAction without subscriptionWith Data-plugin in case, @DataAction returns an Observable, you have to subscribe to the @DataAction function to fire an action itself. Without a subscribe, action will not be fired, and you will not see updates in the store. This can be confusing and unexpected for developers that are used to pure NGXS. Also, it can provide issues while integrating Data-plugin into the projects that were developed a long time without it.
To achieve an origin behavior of Actions you can pass option subscribeRequired with false value to the @DataAction decorator.
The same behavior can be achieved globally for all @DataAction in the app by providing a global config property.
Last updated