0
0
Lập trình
Sơn Tùng Lê
Sơn Tùng Lê103931498422911686980

NgRx Signal Store Event API: Kiến Trúc Hướng Sự Kiện Hiện Đại

Đăng vào 3 tuần trước

• 6 phút đọc

NgRx Signal Store Event API: Kiến Trúc Hướng Sự Kiện Hiện Đại

NgRx Signal Store là một công cụ mạnh mẽ để quản lý trạng thái trong các ứng dụng Angular. Với tính năng mới về sự kiện của NgRx SignalStore, bạn có thể xây dựng các hệ thống hướng sự kiện một cách linh hoạt hơn, giảm thiểu mã nguồn rườm rà.

Giới thiệu

Nếu bạn đã từng làm việc với NgRx Signal Store, bạn sẽ biết rằng đây là một công cụ rất hữu dụng để quản lý trạng thái. Nhưng bạn có biết rằng bạn có thể nâng cấp nó lên một tầm cao mới với kiến trúc hướng sự kiện? Hãy tưởng tượng rằng dòng trạng thái của bạn hoàn toàn tách biệt, cho phép bạn linh hoạt hơn trong việc xử lý các sự kiện mà không cần lo lắng về sự phụ thuộc giữa các hàm và cập nhật trạng thái.

Cách hoạt động

Tính năng Event API mới cung cấp giải pháp sạch sẽ cho vấn đề này. Thay vì các thành phần phải trực tiếp thông báo cho cửa hàng cập nhật trạng thái, chúng chỉ cần phát ra một thông điệp. Ví dụ, khi nhân vật của bạn đánh bại một kẻ thù, nó chỉ cần phát ra thông điệp "Kẻ thù đã bị tiêu diệt!". Các thành phần khác, như trình theo dõi XP, bộ đếm vàng và dịch vụ thông báo UI sẽ lắng nghe và phản ứng tương ứng.

Ví dụ thực tế

Hãy xem xét một kịch bản từ trò chơi của chúng ta. Chúng ta cần xử lý một sự kiện duy nhất: một kẻ thù bị đánh bại. Hành động đơn giản này sẽ kích hoạt một chuỗi phản ứng trong trạng thái của trò chơi.

Định nghĩa trạng thái

Chúng ta sẽ theo dõi các chỉ số cơ bản của nhân vật trong HeroStore:

typescript Copy
// hero.store.ts
export interface HeroState {
  level: number;
  xp: number;
  gold: number;
}

export const initialState: HeroState = {
  level: 1,
  xp: 0,
  gold: 0,
};

Định nghĩa sự kiện

Sự kiện cần chứa dữ liệu cần thiết. Khi một kẻ thù bị đánh bại, chúng ta cần biết số XP và vàng mà nó mang theo.

typescript Copy
// hero.events.ts
import { type } from '@ngrx/signals';
import { eventGroup } from '@ngrx/signals/events';

export const heroPanelEvents = eventGroup({
  source: 'Hero Panel',
  events: {
    enemyDefeated: type<{ xpValue: number; goldDrop: number }>(),
  },
});

export const heroApiEvents = eventGroup({
  source: 'Hero API',
  events: {
    levelUp: type<{ newLevel: number }>(),
  },
});

Cửa hàng HeroStore

Chúng ta kết hợp hai phần quan trọng: reducereffects.

  • Reducer: trách nhiệm của nó là cập nhật trạng thái dựa trên dữ liệu sự kiện.
  • Effects: xử lý các logic phức tạp, tính toán hoặc gọi API mà không thay đổi trực tiếp trạng thái.
typescript Copy
// hero.store.ts
import { signalStore, withState } from '@ngrx/signals';
import { withReducer, on } from '@ngrx/signals/events';
import { heroPanelEvents, heroApiEvents } from './hero.events';
import { withHeroEffects } from './withHeroEffects';

export interface HeroState {
  level: number;
  xp: number;
  gold: number;
}

export const initialState: HeroState = {
  level: 1,
  xp: 0,
  gold: 0,
};

export const HeroStore = signalStore(
  withState<HeroState>(initialState),
  withHeroEffects(),
  withReducer(
    on(heroPanelEvents.enemyDefeated, ({ payload }) => ({ gold, xp }) => ({
      xp: xp + payload.xpValue,
      gold: gold + payload.goldDrop,
    })),
    on(heroApiEvents.levelUp, ({ payload }) => ({
      level: payload.newLevel,
    }))
  )
);

Xử lý sự kiện nâng cấp cấp độ

Logic nâng cấp cấp độ được xử lý trong effects:

typescript Copy
// withHeroEffects.ts
import { inject } from '@angular/core';
import { signalStoreFeature, type } from '@ngrx/signals';
import { withEffects } from '@ngrx/signals/events';
import { Events } from '@ngrx/signals/events';
import { map, switchMap } from 'rxjs';
import { heroPanelEvents, heroApiEvents } from './hero.events';
import { HeroState } from './hero.store';
import { HeroService } from './hero.service';

export function withHeroEffects() {
  return signalStoreFeature(
    type<{ state: HeroState }>(),
    withEffects(
      (
        store, 
        events = inject(Events), 
        heroService = inject(HeroService)
      ) => ({
      levelUpEffect: events.on(heroPanelEvents.enemyDefeated).pipe(
        switchMap(() =>
          heroService.checkLevel(store.xp()).pipe(
            map((newLevel: number) => {
              if (newLevel > store.level()) {
                return heroApiEvents.levelUp({ newLevel });
              }
              return null;
            })
          )
        )
      )
    }))
  );
}

Tích hợp mọi thứ lại với nhau

Bây giờ bạn đã thiết lập cửa hàng, định nghĩa sự kiện và tạo một effect. Vậy bạn sẽ làm gì trong component của mình? Đến đây mọi thứ trở nên dễ dàng.

Nhờ vào APIs injectDispatchsignalStore, code trong component trở nên rất sạch sẽ:

typescript Copy
// hero.component.ts
import { Component, inject } from '@angular/core';
import { HeroStore } from './hero.store';
import { heroPanelEvents } from './hero.events';
import { injectDispatch } from '@ngrx/signals/events';

@Component({
  selector: 'app-hero-panel',
  template: `
    <h2>Hero Stats</h2>
    <p>Level: {{ store.level() }}</p>
    <p>XP: {{ store.xp() }}</p>
    <p>Gold: {{ store.gold() }}</p>
    <button (click)="onEnemyDefeated()">Defeat Enemy</button>
  `,
  providers: [HeroStore],
})
export default class HeroPanelComponent {
  private readonly store = inject(HeroStore);
  private readonly dispatch = injectDispatch(heroPanelEvents);

  onEnemyDefeated() {
    // Chúng ta chỉ cần thông báo rằng một kẻ thù đã bị đánh bại.
    this.dispatch.enemyDefeated({ xpValue: 200, goldDrop: 50 });
  }
}

Kết luận

Với kiến trúc hướng sự kiện mới này, bạn có thể xây dựng một ứng dụng mạnh mẽ và được cấu trúc tốt hơn. Thay vì phải quản lý trạng thái một cách thủ công, bạn chỉ cần thông báo về các sự kiện, và phần còn lại sẽ được tự động xử lý. Khi bạn xây dựng các ứng dụng phức tạp hơn, hãy nghĩ đến cách mà các sự kiện có thể giúp bạn dễ dàng hơn trong việc quản lý trạng thái.

Thực hành tốt nhất

  • Giữ cho các sự kiện đơn giản: Mỗi sự kiện nên chỉ thực hiện một nhiệm vụ cụ thể để dễ dàng quản lý.
  • Tách biệt logic: Sử dụng các effects để xử lý các logic phức tạp thay vì đưa vào reducer.

Những cạm bẫy thường gặp

  • Quá tải sự kiện: Đừng tạo quá nhiều sự kiện cho mọi hành động nhỏ, điều này có thể làm cho mã của bạn trở nên khó hiểu.
  • Không kiểm soát trạng thái: Đảm bảo rằng bạn luôn kiểm soát trạng thái của ứng dụng để tránh lỗi.

Mẹo hiệu suất

  • Sử dụng memoization: Đảm bảo rằng bạn không tính toán lại các giá trị đã được tính toán trước đó.
  • Giảm thiểu số lượng sự kiện: Chỉ phát ra các sự kiện cần thiết để tối ưu hóa hiệu suất.

FAQ

  1. NgRx Signal Store là gì?
    NgRx Signal Store là một công cụ quản lý trạng thái cho Angular, cho phép bạn quản lý trạng thái một cách hiệu quả và dễ dàng.

  2. Làm thế nào để sử dụng Event API?
    Bạn có thể sử dụng Event API để phát ra các sự kiện và lắng nghe chúng trong các thành phần khác nhau mà không cần phải liên kết chặt chẽ với nhau.

  3. Tôi có thể kết hợp NgRx Signal Store với các công nghệ khác không?
    Có, NgRx có thể được tích hợp với nhiều công nghệ khác nhau trong Angular để cải thiện khả năng quản lý trạng thái.

Bằng cách áp dụng những kiến thức và kỹ thuật này, bạn sẽ thấy việc quản lý trạng thái trong ứng dụng Angular của bạn trở nên hiệu quả và dễ dàng hơn bao giờ hết. Hãy bắt đầu thực hành ngay hôm nay!

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào