Angular NgRx Store:
NgRx Store는 Angular 애플리케이션을 위한 상태 관리 라이브러리로, 자바스크립트 애플리케이션의 인기 있는 상태 관리 라이브러리인 Redux에서 영감을 받았습니다. 이 라이브러리는 반응형이며 확장 가능한 방식으로 상태를 관리할 수 있는 예측 가능한 상태 컨테이너를 제공합니다.
NgRx Store의 주요 개념
- Store: 애플리케이션의 상태를 보관하는 곳입니다. Store는 단일 진실의 출처(single source of truth)로, 애플리케이션의 모든 상태를 중앙에서 관리합니다.
- State: 애플리케이션의 현재 상태를 나타냅니다. 상태는 일반적으로 여러 작은 상태 조각으로 나뉘어 관리됩니다.
- Actions: 상태 변화를 일으키는 이벤트입니다. Action은 type과 선택적으로 payload를 포함합니다.
- Reducers: Actions에 따라 상태를 변화시키는 순수 함수입니다. Reducer는 현재 상태와 Action을 입력으로 받아 새로운 상태를 반환합니다.
- Selectors: Store에서 상태를 추출하는 함수입니다. Selectors는 애플리케이션의 특정 부분에 접근할 수 있게 도와줍니다.
- Effects: 비동기 작업을 관리하기 위한 NgRx의 컴포넌트입니다. Effects는 Action을 관찰하고 비동기 작업(예: HTTP 요청)을 수행한 후 새로운 Action을 디스패치합니다.
전체적인 흐름
1. example.actions.ts
2. example.actions.ts
3. example.effects.ts
4. example.reducers.ts
example.selectors.ts
import { createFeatureSelector, createSelector } from '@ngrx/store';
export const selectExamplesState = createFeatureSelector<ExampleType[]>('examples');
export const selectExamples = createSelector(selectExamplesState, (examples: ExampleType[]) => examples);
- import { createFeatureSelector } from '@ngrx/store';:
- NgRx 패키지에서 createFeatureSelector 함수를 가져옵니다. 이 함수는 NgRx 스토어에서 특정 피처 상태를 선택하는 데 사용됩니다.
- createFeatureSelector<ExampleType[]>('examples')
- createFeatureSelector는 NgRx 스토어에서 특정 피처 상태 슬라이스를 선택하는 데 사용됩니다.
- ExampleType[]는 'examples' 상태 슬라이스의 타입입니다.
- 'examples'는 상태 슬라이스의 이름입니다. 이 이름은 보통 상태 모듈을 설정할 때 정의됩니다.
- 결과적으로, selectExamplesState는 NgRx 스토어에서 'examples' 상태 슬라이스를 선택하는 선택자 함수가 됩니다.
- createSelector(selectExamplesState, (examples: ExampleType[]) => examples)
- createSelector는 입력 선택자들(selectExamplesState)과 프로젝션 함수((examples) => examples)를 인자로 받아 새로운 선택자를 만듭니다.
- selectExamplesState는 첫 번째 선택자로, 'examples' 상태 슬라이스를 반환합니다.
- 프로젝션 함수 (examples: ExampleType[]) => examples는 이 상태 슬라이스를 받아 그대로 반환합니다. 이는 선택자를 통해 'examples' 상태 슬라이스를 그대로 가져오는 역할을 합니다.
- 결과적으로, selectExamples는 selectExamplesState와 같은 역할을 하지만, 이를 통해 추가적인 프로젝션이나 변환을 적용할 수 있는 구조를 제공합니다.
Selector 사용법
import { selectExamplesState } from 'path-to-selectors-file';
import { Store } from '@ngrx/store';
@Component({
// Component metadata here
})
export class SomeComponent implements OnInit {
examples$: Observable<ExampleType[]>;
constructor(private store: Store) {}
ngOnInit() {
this.examples$ = this.store.select(selectExamplesState);
}
}
Selector 후 전체 동작 흐름
- 액션 생성:
- createExample 함수가 호출되어 { viewMode: this.viewMode } 페이로드를 포함한 액션 객체를 만듭니다.
- 생성된 액션 객체는 다음과 같을 수 있습니다:
- 액션 디스패치:
- this.store.dispatch(createExample({ viewMode: this.viewMode }))가 호출됩니다.
- 이펙트 처리:
- ExampleEffects에서 createExample 액션을 포착합니다.
- ExampleService를 사용하여 비동기 작업(API 호출)을 수행합니다.
- 작업이 성공하면 createExampleSuccess 액션을, 실패하면 createExampleFailure 액션을 디스패치합니다.
- 리듀서 처리:
- 스토어는 디스패치된 액션을 받아 리듀서로 전달합니다.
- 성공 액션(createExampleSuccess)이 리듀서에 전달되면, 새로운 보드가 상태에 추가됩니다.
- 실패 액션(createExampleFailure)이 리듀서에 전달되면, 오류 상태가 업데이트됩니다.
1. 액션 (example.actions.ts)
import { createAction, props } from '@ngrx/store';
export const createExample = createAction(
'[Example] Create Example',
props<{ viewMode: string }>()
);
export const createExampleSuccess = createAction(
'[Example] Create Example Success',
props<{ example: ExampleType }>()
);
export const createExampleFailure = createAction(
'[Example] Create Example Failure',
props<{ error: any }>()
);
this.store.dispatch
- store.dispatch는 NgRx 스토어의 메서드로, 액션을 스토어에 전달하여 상태 변화를 유도합니다.
this.store.dispatch(createExample({ viewMode: this.viewMode }));
- dispatch 메서드:
- 스토어의 dispatch 메서드는 액션 객체를 스토어에 전달하여 리듀서가 이를 처리하고 상태를 변경하도록 합니다.
- createExample 액션 생성자:
- 이 함수는 액션 객체를 반환합니다. 예를 들어, 다음과 같이 정의될 수 있습니다:
import { createAction, props } from '@ngrx/store'; export const createExample = createAction('[Examples] Create Example', props<{ viewMode: ExampleFilterTypes }>()); - { viewMode: this.viewMode }:
- createExample 액션 생성자 함수에 전달되는 페이로드입니다. this.viewMode는 현재 클래스의 viewMode 속성으로, Example 생성 시 필요한 상태나 모드를 나타냅니다.
- 예를 들어, this.viewMode가 'ExampleFilterTypes'라면, 이 호출은 createExample 액션을 { viewMode: ExampleFilterTypes } 페이로드와 함께 디스패치합니다.
요약
- this.store.dispatch(createExample({ viewMode: this.viewMode })):
- createExample 액션을 디스패치하여 새로운 Example를 생성하고, 이 보드의 viewMode는 this.viewMode에서 가져온 값을 사용합니다.
- 이를 통해 상태가 변경되고, 새로운 Example이 NgRx 스토어에 추가됩니다.
2. 이펙트 (example.effect.ts)
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { ExampleService } from './example.service';
import { createExample, createExampleSuccess, createExampleFailure } from './example.actions';
@Injectable()
export class ExampleEffects {
constructor(
private actions$: Actions,
private exampleService: ExampleService
) {}
createExample$ = createEffect(() =>
this.actions$.pipe(
ofType(Actions.createExample),
switchMap(({ viewMode }) =>
from(this.apiCreateExample()).pipe(
switchMap(({ result, errorCode, errorMessage, data }) => {
if (result) {
return of(ExampleActions.createExampleSuccess({ data, viewMode }));
} else {
return of(ExampleActions.fromServerFailure({ error: { errorCode, errorMessage } }));
}
}),
catchError((error) => of(ExampleActions.genericFailure({ error: error.message })))
)
)
)
);
}
- createEffect:
- NgRx 이펙트를 정의하는 함수입니다. 이펙트는 액션 스트림을 관찰하고, 특정 액션에 반응하여 비동기 작업을 수행합니다.
- this.actions$.pipe:
- this.actions$는 NgRx에서 제공하는 액션 스트림입니다. 모든 디스패치된 액션이 이 스트림을 통해 전달됩니다.
- pipe 메서드를 사용하여 액션 스트림을 조작합니다.
- ofType(Actions.createExample):
- ofType는 특정 타입의 액션을 필터링합니다. 여기서는 createExample 액션이 디스패치될 때만 이펙트가 실행되도록 합니다.
- switchMap(({ viewMode }) =>:
- switchMap은 새로운 Observable을 생성하며, 이전 Observable을 취소하고 새로운 Observable을 구독합니다.
- 여기서는 createExample 액션의 페이로드인 viewMode를 구조 분해하여 사용합니다.
- from(this.createExample()).pipe:
- from 함수는 프로미스를 Observable로 변환합니다. this.createExample()는 보드 생성 API 호출을 나타냅니다.
- switchMap(({ result, errorCode, errorMessage, data }) =>:
- API 호출의 응답을 처리합니다. 응답 객체를 구조 분해하여 result, errorCode, errorMessage, data를 사용합니다.
- 성공 처리:
- if (result) { ... } 블록은 API 호출이 성공했을 때 실행됩니다.
- Actions.createExampleSuccess({ data, viewMode }) 액션을 디스패치하여 성공 상태를 반영합니다.
- 실패 처리:
- else { ... } 블록은 API 호출이 실패했을 때 실행됩니다.
- 오류가 발생하면, ExampleActions.fromServerFailure({ error: { errorCode, errorMessage } }) 액션을 디스패치합니다.
- catchError:
- API 호출 도중 발생한 에러를 처리합니다.
- ExampleActions.genericFailure({ error: error.message }) 액션을 디스패치하여 에러 상태를 반영합니다.
3. 리듀서 (example.reducer.ts)
import { createReducer, on } from '@ngrx/store';
import { createExampleSuccess, createExampleFailure } from './example.actions';
export const initialState = {
examples: [],
error: null
};
const exampleReducer = createReducer(
initialState,
on(createExampleSuccess, (state, { example }) => ({
...state,
examples: [...state.examples, example],
error: null
})),
on(createExampleFailure, (state, { error }) => ({
...state,
error
}))
);
export function reducer(state, action) {
return exampleReducer(state, action);
}
- NgRx를 사용하여 보드 관련 상태를 관리하는 리듀서를 정의합니다.
- 리듀서는 특정 액션에 따라 상태를 변경하는 역할을 합니다.
- 여기서 examplesReducer는 createExampleSuccess 액션이 디스패치될 때 상태를 업데이트하는 방법을 정의합니다.
'개발 공부 > Angular' 카테고리의 다른 글
| Angular LifeCycle (1) | 2024.11.02 |
|---|---|
| Angular Standalone (2) | 2024.10.27 |
| Angular 란 (0) | 2024.07.21 |
| Angular / RxJS (0) | 2024.07.16 |
| Service Workers (1) | 2024.01.24 |