본문 바로가기

개발 공부/Angular

NgRx Component Store: 컴포넌트 중심의 상태 관리

NgRx Component Store

 

1. Component Store

NgRx Component Store는 NgRx에서 제공하는 경량 상태 관리 도구로, 전역 상태가 아닌 컴포넌트별 상태를 효율적으로 관리하기 위해 설계되었습니다.

컴포넌트 로컬 상태를 처리하는 데 최적화되어 있으며, 기존 NgRx와 유사한 패턴을 사용하지만 더 간결한 코드로 상태를 관리할 수 있습니다.

 

2. 주요 특징

  • 컴포넌트 중심: 개별 컴포넌트 또는 기능 모듈에 국한된 상태를 관리.
  • RxJS 기반: 반응형 데이터 흐름 관리.
  • 가벼움: 전역 상태 관리 툴(NgRx Store)에 비해 설정 및 유지 보수가 간단.
  • 구독 기반 상태 관리: RxJS의 Observable을 활용한 상태 변경 구독.

3. 기본 구조

NgRx Component Store는 다음 네 가지 주요 개념으로 구성됩니다

  • State: 관리할 상태를 정의.
  • Updater: 상태를 수정하는 함수.
  • Selector: 상태를 읽는 함수.
  • Effect: 비동기 작업을 처리하고 상태를 업데이트.

4. Component Store의 장점

  • 경량 상태 관리: 컴포넌트 단위 상태 관리에 최적화.
  • 코드 간결화: 전역 상태 관리 도구에 비해 설정이 간단.
  • 비동기 작업 처리: RxJS의 Effect로 쉽게 비동기 작업 관리.

5. Component Store의 단점

  • 전역 상태 관리에는 부적합: 큰 규모의 애플리케이션에서는 적합하지 않을 수 있음.
  • RxJS 의존성: RxJS에 익숙하지 않다면 학습이 필요.

간단한 예제: Todo 애플리케이션

1) 설치

npm install @ngrx/component-store

 

2) Component Store 생성

 

Todo 상태를 관리하는 TodoStore를 작성합니다.

import { Injectable } from '@angular/core';
import { ComponentStore } from '@ngrx/component-store';

export interface Todo {
  id: number;
  title: string;
  completed: boolean;
}

export interface TodoState {
  todos: Todo[];
}

@Injectable()
export class TodoStore extends ComponentStore<TodoState> {
  constructor() {
    super({ todos: [] });
  }

  // 상태 읽기
  readonly todos$ = this.select(state => state.todos);

  // 상태 수정 (업데이트)
  readonly addTodo = this.updater((state, newTodo: Todo) => ({
    todos: [...state.todos, newTodo],
  }));

  readonly toggleTodoCompletion = this.updater((state, id: number) => ({
    todos: state.todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ),
  }));
}

 

 

  • Todo 인터페이스: 각 Todo 항목의 구조를 정의합니다.
    • id: Todo의 고유 ID.
    • title: Todo의 제목.
    • completed: 완료 여부를 나타내는 boolean 값.
  • TodoState 인터페이스: 애플리케이션의 상태를 정의합니다.
    • todos: Todo 객체의 배열로, Todo 목록을 저장합니다.
  • TodoStore:
    • ComponentStore<TodoState>를 상속받아 상태를 관리하는 클래스입니다.
    • super({ todos: [] }): 초기 상태를 정의합니다. todos는 빈 배열로 시작합니다.
  • @Injectable():
    • 이 클래스는 Angular의 DI(Dependency Injection) 시스템을 통해 컴포넌트에 주입될 수 있습니다.
  • todos$:
    • select 메서드를 사용하여 TodoState에서 todos 배열을 선택합니다.
    • 상태를 관찰 가능한 스트림(Observable)로 반환하여, 구독자가 상태 변경 사항을 자동으로 반영할 수 있습니다.
  • addTodo:
    • 새로운 Todo 항목을 추가하는 업데이트 함수입니다.
    • state: 현재 상태를 나타냅니다.
    • newTodo: 추가할 Todo 항목.
    • 작동 방식:
      1. 현재 상태(state.todos)를 가져옵니다.
      2. 새로운 Todo를 기존 배열에 추가하여 새로운 상태를 반환합니다.
    • toggleTodoCompletion:
      • 특정 Todo 항목의 completed 상태를 반전(토글)합니다.
      • 작동 방식:
        1. state.todos 배열을 순회하며, id가 일치하는 Todo 항목을 찾습니다.
        2. 해당 Todo 항목의 completed 값을 반전시킵니다.
        3. 나머지 항목은 변경하지 않고 그대로 반환합니다.

 

 

3) 컴포넌트에서 사용

컴포넌트에서 TodoStore를 주입받아 상태를 관리합니다.

import { Component } from '@angular/core';
import { TodoStore } from './todo.store';

@Component({
  selector: 'app-todo',
  template: `
    <div *ngFor="let todo of todos$ | async">
      <label>
        <input type="checkbox" [checked]="todo.completed" (change)="toggle(todo.id)" />
        {{ todo.title }}
      </label>
    </div>
    <input #todoInput type="text" placeholder="Add Todo" (keydown.enter)="add(todoInput.value); todoInput.value=''" />
  `,
  providers: [TodoStore],
})
export class TodoComponent {
  todos$ = this.todoStore.todos$;

  constructor(private todoStore: TodoStore) {}

  add(title: string) {
    const newTodo = { id: Date.now(), title, completed: false };
    this.todoStore.addTodo(newTodo);
  }

  toggle(id: number) {
    this.todoStore.toggleTodoCompletion(id);
  }
}

 

 

  • 상태 읽기:
    • todos$를 템플릿에서 *ngFor와 함께 사용하여 Todo 목록을 출력합니다.
  • 상태 수정:
    • add 메서드: 새로운 Todo를 추가.
    • toggle 메서드: Todo 완료 상태를 토글.

 

'개발 공부 > Angular' 카테고리의 다른 글

Query Parameters / Angular  (1) 2024.11.26
Angular Router Guards  (1) 2024.11.24
Angular Signals (2)  (0) 2024.11.21
Angular Signals (1)  (1) 2024.11.20
BehaviorSubject를 활용한 View 상태 관리  (0) 2024.11.17