• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Announcing Events Plugin for NgRx SignalStore: A Modern Take on Flux Architecture

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
We are pleased to announce the introduction of the Events plugin for NgRx SignalStore, released as part of NgRx v19.2! This new addition brings the power of event-based state management to SignalStore, enabling developers to create scalable applications more effectively.

Experimental Stage ?


The Events plugin is currently marked as experimental. This means its APIs are subject to change, and modifications may occur in future versions without standard breaking change announcements until it is deemed stable. We encourage you to try it out, provide feedback, and help shape its future!

Flux Architecture ?


This plugin takes inspiration from the original Flux architecture and incorporates the best practices and patterns from NgRx Store, NgRx Effects, and RxJS.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



The application architecture with the Events plugin is composed of the following building blocks:

  1. Event: Describes an occurrence within the system. Events are dispatched to trigger state changes and/or side effects.
  2. Dispatcher: An event bus that forwards events to their corresponding handlers in the stores.
  3. Store: Contains reducers and effects that manage state and handle side effects, maintaining a clean and predictable application flow.
  4. View: Reflects state changes and dispatches new events, enabling continuous interaction between the user interface and the underlying system.

By dispatching events and reacting to them, the what (the event that occurred) is decoupled from the how (the state changes or side effects that result), leading to predictable data flow and more maintainable code.

Walkthrough ?️


The Events plugin provides a set of APIs for defining and handling events in a reactive and declarative manner. The following example demonstrates how these APIs can be used to implement state and behavior orchestration through events.

Defining Events


Events are created using the eventGroup function, which organizes related events under a common source. This function accepts an object with two properties:

  • source: identifies the origin of the event group (e.g., 'Users Page', 'Users API').
  • events: a dictionary of named event creators, where each key defines the event name and each value defines the payload type using the type helper from the core @ngrx/signals package.

import { type } from '@ngrx/signals';
import { eventGroup } from '@ngrx/signals/events';

export const usersPageEvents = eventGroup({
source: 'Users Page',
events: {
opened: type<void>(),
refreshed: type<void>(),
},
});

export const usersApiEvents = eventGroup({
source: 'Users API',
events: {
loadedSuccess: type<User[]>(),
loadedFailure: type<string>(),
},
});
Performing State Changes


To handle state changes in response to events, SignalStore provides the withReducer feature. Case reducers are defined using the on function, which maps one or more events to a case reducer function. Each case reducer receives the event and returns the state update. It supports three forms of return values: a partial state object, a partial state updater, and an array of partial state objects and/or updaters.


import { signalStore } from '@ngrx/signals';
import { setAllEntities, withEntities } from '@ngrx/signals/entities';
import { on, withReducer } from '@ngrx/signals/events';

export const UsersStore = signalStore(
{ providedIn: 'root' },
withEntities<User>(),
withRequestStatus(),
withReducer(
on(usersPageEvents.opened, usersPageEvents.refreshed, setPending),
on(usersApiEvents.loadedSuccess, ({ payload }) => [
setAllEntities(payload),
setFulfilled(),
]),
on(usersApiEvents.loadedFailure, ({ payload }) => setError(payload)),
),
);
? Implementation of the withRequestStatus feature and its state updaters is available in the official

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

.
Performing Side Effects


Side effects are handled using the withEffects feature. This feature accepts a function that receives the store instance as an argument and returns a dictionary of effects. Each effect is defined as an observable that reacts to specific events using the Events service. If an effect emits a new event, that event will be automatically dispatched.


import { Events, withEffects } from '@ngrx/signals/events';
import { mapResponse } from '@ngrx/operators';

export const UsersStore = signalStore(
/* ... */
withEffects(
(
store,
events = inject(Events),
usersService = inject(UsersService),
) => ({
loadUsers$: events
.on(usersPageEvents.opened, usersPageEvents.refreshed)
.pipe(
exhaustMap(() =>
usersService.getAll().pipe(
mapResponse({
next: (users) => usersApiEvents.loadedSuccess(users),
error: (error: { message: string }) =>
usersApiEvents.loadedFailure(error.message),
}),
),
),
),
logError$: events
.on(usersApiEvents.loadedFailure)
.pipe(tap(({ payload }) => console.log(payload))),
}),
),
);
Reading State


The plugin doesn’t change how the state is exposed or consumed. Therefore, components can access state and computed signals by using the store instance.


@Component({
selector: 'app-users',
template: `
<h1>Users</h1>

@if (usersStore.isPending()) {
<p>Loading...</p>
}

<ul>
@for (user of usersStore.entities(); track user.id) {
<li>{{ user.name }}</li>
}
</ul>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UsersComponent {
readonly usersStore = inject(UsersStore);
}
Dispatching Events


To initiate state changes or side effects, events can be dispatched using the Dispatcher service. It provides a dispatch method that takes an event as input.


import { Dispatcher } from '@ngrx/signals/events';

@Component({
/* ... */
template: `
<h1>Users</h1>

<button (click)="refresh()">Refresh</button>
`,
})
export class UsersComponent {
readonly usersStore = inject(UsersStore);
readonly dispatcher = inject(Dispatcher);

constructor() {
this.dispatcher.dispatch(usersPageEvents.opened());
}

refresh(): void {
this.dispatcher.dispatch(usersPageEvents.refreshed());
}
}

For convenience, self-dispatching events can be generated using the injectDispatch function, which returns an object with methods matching the provided event creators.


import { injectDispatch } from '@ngrx/signals/events';

@Component({
/* ... */
template: `
<h1>Users</h1>

<button (click)="dispatch.refreshed()">Refresh</button>
`,
})
export class UsersComponent {
readonly usersStore = inject(UsersStore);
readonly dispatch = injectDispatch(usersPageEvents);

constructor() {
this.dispatch.opened();
}
}
Scaling Up


As applications grow in complexity, reducers and effects can be extracted into standalone features to improve maintainability.

Extracted Reducer


export function withUsersReducer() {
return signalStoreFeature(
{ state: type<EntityState<User> & RequestStatusState>() },
withReducer(
on(usersPageEvents.opened, usersPageEvents.refreshed, setPending),
on(usersApiEvents.loadedSuccess, ({ payload }) => [
setAllEntities(payload),
setFulfilled(),
]),
on(usersApiEvents.loadedFailure, ({ payload }) => setError(payload)),
),
);
}

Extracted Effects


export function withUsersEffects() {
return signalStoreFeature(
withEffects(
(
store,
events = inject(Events),
usersService = inject(UsersService),
) => ({
loadUsers$: events
.on(usersPageEvents.opened, usersPageEvents.refreshed)
.pipe(
exhaustMap(() =>
usersService.getAll().pipe(
mapResponse({
next: (users) => usersApiEvents.loadedSuccess(users),
error: (error: { message: string }) =>
usersApiEvents.loadedFailure(error.message),
}),
),
),
),
logError$: events
.on(usersApiEvents.loadedFailure)
.pipe(tap(({ payload }) => console.log(payload))),
}),
),
);
}

Final Store Composition


export const UsersStore = signalStore(
{ providedIn: 'root' },
withEntities<User>(),
withRequestStatus(),
withUsersReducer(),
withUsersEffects(),
);
Key Takeaways ?


The Events plugin:

  • Combines proven patterns from Flux, NgRx Store, NgRx Effects, and RxJS.
  • Seamlessly integrates with existing SignalStore features.
  • Extends Flux architecture with powerful customization options.
  • Unifies local and global state management with a single approach.
Upcoming NgRx Workshops ?


With NgRx usage continuing to grow with Angular, many developers and teams still need guidance on how to architect and build enterprise-grade Angular applications. We are excited to introduce upcoming workshops provided directly by the NgRx team!

We're offering one to three full-day workshops that cover the basics of NgRx to the most advanced topics. Whether your teams are just starting with NgRx or have been using it for a while - they are guaranteed to learn new concepts during these workshops.

Visit our

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

for more details. The next workshops are scheduled for:

Thanks to All Our Contributors and Sponsors! ?


NgRx continues to be a community-driven project. Design, development, documentation, and testing - all are done with the help of the community. Visit our

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

to see every person who has contributed to the framework.

If you are interested in contributing, visit our

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

and look through our open issues, some marked specifically for new contributors. We also have active GitHub discussions for new features and enhancements.

We want to give a big thanks to our Gold sponsor,

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

! Nx has been a longtime promoter of NgRx as a tool for building Angular applications and is committed to supporting open-source projects that they rely on.

We want to thank our Bronze sponsor,

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

!

Lastly, we also want to thank our individual sponsors who have donated once or monthly.

Sponsor NgRx ?


If you are interested in sponsoring the continued development of NgRx, please visit our

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

for different sponsorship options, or

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

directly to discuss other sponsorship opportunities.

Follow us on

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

and

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

for the latest updates about the NgRx platform.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу