이 글은 여러분에게 Angular의 상태 관리자 NgRx에 대한 심층적인 이해를 제공하고 NgRx 사용 방법을 소개할 것입니다. 도움이 되길 바랍니다!
NgRx는 Angular 애플리케이션의 전역 상태 관리를 위한 Redux 아키텍처 솔루션입니다. [관련 추천 튜토리얼: "Angular 튜토리얼"]
@ngrx/store: 전역 상태 관리 모듈
@ngrx/효과: 부작용 처리
@ngrx/store-devtools: 브라우저 디버깅 도구, Redux Devtools Extension에 의존해야 함
@ngrx/schematics: NgRx 파일을 빠르게 생성하는 명령줄 도구
@ngrx/entity: 개발자의 Reducer 데이터 운영 효율성 향상
@ngrx/router-store: 라우팅 상태를 글로벌 스토어에 동기화
1. NgRx 다운로드
npm install @ngrx/store @ngrx/effects @ngrx/entity @ngrx/router-store @ngrx/store-devtools @ngrx/schematics
2. NgRx CLI 구성
ng config cli.defaultCollection @ngrx/schematics
// 각도.json "cli": { "defaultCollection": "@ngrx/schematics" }
3. 스토어 생성
ng g store State --root --module app.module.ts --statePath store --stateInterface AppState
4. 액션 생성
ng g action store/actions/counter --skipTests
"@ngrx/store"에서 { createAction } 가져오기 const 증분 내보내기 = createAction("증분") const 감소 = createAction("감소") 내보내기
5. 리듀서 생성
ng g reducer store/reducers/counter --skipTests --reducers=../index.ts
"@ngrx/store"에서 가져오기 { createReducer, on } "../actions/counter.actions"에서 { 감소, 증가 } 가져오기 const counterFeatureKey = "카운터" 내보내기 내보내기 인터페이스 상태 { 개수: 숫자 } constinitialState 내보내기: 상태 = { 개수: 0 } const 감속기 내보내기 = createReducer( 초기 상태, on(증분, 상태 => ({ 개수: state.count + 1 })), on(감소, 상태 => ({ 개수: state.count - 1 })) )
6. 선택기 생성
ng g selector store/selectors/counter --skipTests
"@ngrx/store"에서 { createFeatureSelector, createSelector } 가져오기 "../reducers/counter.reducer"에서 { counterFeatureKey, State } 가져오기 ".."에서 { AppState } 가져오기 내보내기 const selectCounter = createFeatureSelector<AppState, State>(counterFeatureKey) const selectCount = createSelector(selectCounter, state => state.count) 내보내기
7. 컴포넌트 클래스는 Action을 트리거하고 상태를 획득합니다.
"@ngrx/store"에서 { 선택, 저장 } 가져오기 "rxjs"에서 { Observable } 가져오기 "./store"에서 { AppState } 가져오기 "./store/actions/counter.actions"에서 { 감소, 증가 } 가져오기 "./store/selectors/counter.selectors"에서 { selectCount } 가져오기 내보내기 클래스 AppComponent { 개수: 관찰 가능<숫자> constructor(개인 저장소: Store<AppState>) { this.count = this.store.pipe(select(selectCount)) } 증분() { this.store.dispatch(증분()) } 감소() { this.store.dispatch(감소()) } }
8. 컴포넌트 템플릿 표시 상태
<버튼(클릭)="증분()">+</버튼> <span>{{ 비동기 }}</span> <버튼(클릭)="감소()">-</버튼>
1. Action을 트리거할 때 구성 요소의 디스패치를 사용하여 매개 변수를 전달하면 매개 변수가 결국 Action 개체에 배치됩니다.
this.store.dispatch(increment({ count: 5 }))
2. Action Creator 기능을 생성할 때 매개변수를 얻고 매개변수 유형을 지정합니다.
"@ngrx/store"에서 { createAction, props } 가져오기 const increment = createAction("increment", props<{ count: number }>()) 내보내기
내보내기 선언 함수 props<P 확장 객체>(): Props<P>;
3. Reducer의 Action 객체를 통해 매개변수를 얻습니다.
const 감속기 내보내기 = createReducer( 초기 상태, on(증가, (상태, 동작) => ({ 개수: state.count + action.count })) )
MetaReducer는 Action -> Reducer 사이의 후크로, 개발자가 Action(일반 Reducer 함수 호출 전에 호출됨)을 전처리할 수 있도록 해줍니다.
function debug(reducer: ActionReducer<any>): ActionReducer<any> { 반환 함수(상태, 동작) { 반환 감속기(상태, 동작) } } const MetaReducers 내보내기: MetaReducer<AppState>[] = !environment.production ?[디버그] : []
요구 사항: 페이지에 버튼을 추가한 후 값이 증가할 때까지 1초 정도 지연하세요.
1. 컴포넌트 템플릿에 비동기 값 증가를 위한 버튼을 추가합니다. 버튼을 클릭하면 increment_async
메서드가 실행됩니다.
<button (click)="increment_async()">비동기</button>
2. increment_async
메서드를 구성 요소 클래스에 추가하고 작업을 트리거하여 메서드에서 비동기 작업을 수행합니다.
increment_async() { this.store.dispatch(increment_async()) }
3. 액션 파일에서 비동기 작업을 수행하기 위한 액션을 추가합니다.
const increment_async = createAction("increment_async") 내보내기
4. Effect를 생성하고, Action을 수신하고, Side Effect를 수행하고, 계속해서 Action을 트리거합니다.
ng g effect store/effects/counter --root --module app.module.ts --skipTests
Effect 함수는 @ngrx/효과 모듈에서 제공되므로 관련 모듈 종속성을 루트 모듈로 가져와야 합니다.
"@angular/core"에서 { 주입 가능 } 가져오기 "@ngrx/효과"에서 { Actions, createEffect, ofType } 가져오기 "../actions/counter.actions"에서 { 증가, increment_async } 가져오기 "rxjs/operators"에서 { mergeMap, map } 가져오기 "rxjs"에서 { 타이머 } 가져오기 // 효과 생성 // Effect를 생성하는데 사용되며, Effect는 Side Effect를 수행하는데 사용됩니다. // 메소드 호출 시 콜백 함수를 전달하고, 콜백 함수에 Observable 객체를 반환합니다. Side Effect가 실행된 후 트리거되는 Action 객체입니다. // 콜백 함수의 반환 값은 createEffect 내부에서 계속 반환됩니다. 메서드 및 최종 반환 값은 Effect 클래스의 속성에 저장됩니다. // Effect 클래스를 인스턴스화한 후 NgRx는 부작용 클래스 속성을 구독하고 트리거할 Action 개체를 얻습니다. 그리고 액션을 트리거합니다. //행위 // 구성요소가 Action을 트리거할 때 Effect는 Actions 서비스를 통해 Action을 수신해야 하므로 Effect 클래스에서는 Actions 서비스 클래스의 인스턴스 객체가 생성자 매개변수를 통해 // 인스턴스를 Effect 클래스에 주입합니다. Actions 서비스 클래스의 객체는 Observable입니다. Action이 트리거되면 Action 객체 자체가 // ofType 데이터 스트림으로 방출됩니다. // 대상 Action 객체를 필터링합니다. // 매개변수는 대상 Action의 Action Creator 함수입니다. // 대상 Action 객체가 필터링되지 않으면 이번에는 데이터 스트림이 계속 전송되지 않습니다. // 대상 Action 객체가 필터링되면 Action 객체가 전송됩니다. @Injectable() 데이터 스트림으로 계속 전송됩니다. 내보내기 클래스 CounterEffects { 생성자(비공개 작업: 작업) { // this.loadCount.subscribe(console.log) } loadCount = createEffect(() => { this.actions.pipe( ofType(increment_async), mergeMap(() => 타이머(1000).pipe(map(() => 증분({ 개수: 10 })))) ) }) }
1. 개요
엔터티는 엔터티로 번역되며 엔터티는 컬렉션의 데이터 조각입니다.
NgRx는 엔터티 어댑터 개체를 제공하며, 그 목적은 개발자가 엔터티를 운영하는 효율성을 높이는 것입니다.
2. 코어
1. EntityState: 엔터티 유형 인터페이스
/* { ID: [1, 2], 엔터티: { 1: { ID: 1, 제목: "Hello Angular" }, 2: { ID: 2, 제목: "Hello NgRx" } } } */ 내보내기 인터페이스 State는 EntityState<Todo> {}를 확장합니다.
2. createEntityAdapter: 엔터티 어댑터 객체 생성
3. EntityAdapter: 엔터티 어댑터 객체 유형 인터페이스
const 어댑터 내보내기: EntityAdapter<Todo> = createEntityAdapter<Todo>() // 초기 상태를 가져옵니다. 객체 매개변수를 전달할지 여부는 // {ids: [], 엔터티: {}}입니다. const 초기화 상태 내보내기: 상태 = 어댑터.getInitialState()
3. 인스턴스 방법
https://ngrx.io/guide/entity/adapter#adapter-collection-methods
4. 선택기
// selectTotal은 데이터 항목 수를 가져옵니다. // selectAll은 모든 데이터를 가져와 배열 형태로 표시합니다. // selectEntities는 엔터티 컬렉션을 가져와 사전 형태로 표시합니다. // selectIds는 id 컬렉션을 가져와 표시합니다. 배열 형식입니다. const { selectIds, selectEntities, selectAll, selectTotal } = Adapter .getSelectors();
내보내기 const selectTodo = createFeatureSelector<AppState, State>(todoFeatureKey) const selectTodos = createSelector(selectTodo, selectAll) 내보내기
1. 라우팅 상태 동기화
1) 모듈 소개
"@ngrx/router-store"에서 { StoreRouterConnectingModule } 가져오기 @NgModule({ 수입: [ StoreRouterConnectingModule.forRoot() ] }) 내보내기 클래스 AppModule {}
2) 라우팅 상태를 Store에 통합
"@ngrx/router-store"에서 fromRouter로 * 가져오기 내보내기 인터페이스 AppState { 라우터: fromRouter.RouterReducerState } const 감속기 내보내기: ActionReducerMap<AppState> = { 라우터: fromRouter.routerReducer }
2. 라우팅 상태를 얻기 위한 선택기를 생성합니다.
// router.selectors.ts "@ngrx/store"에서 { createFeatureSelector } 가져오기 ".."에서 { AppState } 가져오기 "@ngrx/router-store"에서 { RouterReducerState, getSelectors } 가져오기 const selectRouter = createFeatureSelector<AppState, RouterReducerState>( "라우터" ) 수출 const { // 현재 경로와 관련된 정보를 가져옵니다(라우팅 매개변수, 라우팅 구성 등). 현재 경로 선택, // 주소 표시줄의 # 숫자 뒤의 콘텐츠를 가져옵니다. selectFragment, // 라우팅 쿼리 매개변수 가져오기 selectQueryParams, // 특정 쿼리 매개변수 가져오기 selectQueryParam('name') selectQueryParam, // 동적 라우팅 매개변수 가져오기 selectRouteParams, // 특정 동적 라우팅 매개변수 가져오기 selectRouteParam('name') selectRouteParam, // 경로 사용자 정의 데이터 가져오기 selectRouteData, // 경로 selectUrl의 실제 액세스 주소를 가져옵니다. } = getSelectors(selectRouter)
// home.comComponent.ts "@ngrx/store"에서 { 선택, 저장 } 가져오기 "src/app/store"에서 {AppState} 가져오기 "src/app/store/selectors/router.selectors"에서 { selectQueryParams } 가져오기 내보내기 클래스 AboutComponent { constructor(개인 저장소: Store<AppState>) { this.store.pipe(select(selectQueryParams)).subscribe(console.log) } }