Эта статья даст вам более глубокое понимание менеджера состояний Angular NgRx и расскажет, как использовать NgRx. Надеюсь, она будет вам полезна!
NgRx — это архитектурное решение Redux для глобального управления состоянием в приложениях Angular. [Рекомендуемые связанные учебные пособия: «учебник по Angular»]
@ngrx/store: модуль управления глобальным состоянием
@ngrx/effects: обработка побочных эффектов.
@ngrx/store-devtools: инструмент отладки браузера, необходимо использовать расширение Redux Devtools Extension.
@ngrx/schematics: инструмент командной строки для быстрого создания файлов NgRx.
@ngrx/entity: повышение эффективности работы разработчиков с данными в Редукторе.
@ngrx/router-store: синхронизировать статус маршрутизации с глобальным хранилищем.
1. Загрузите NgRx
npm install @ngrx/store @ngrx/effects @ngrx/entity @ngrx/router-store @ngrx/store-devtools @ngrx/schematics
2. Настройте CLI NgRx.
ng config cli.defaultCollection @ngrx/schematics
// angular.json "кли": { "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
импортируйте { createAction } из "@ngrx/store" экспортировать константное приращение = createAction("инкремент") экспортировать константный декремент = createAction("декремент")
5. Создать редуктор
ng g reducer store/reducers/counter --skipTests --reducers=../index.ts
импортировать { createReducer, on } из "@ngrx/store" импортировать {уменьшить, увеличить} из "../actions/counter.actions" экспортировать const counterFeatureKey = "счетчик" состояние интерфейса экспорта { счет: число } экспортировать const InitialState: State = { количество: 0 } экспортировать константный редуктор = createReducer( начальное состояние, on(increment,state => ({count:state.count + 1 })), on(декремент, состояние => ({ count: state.count - 1 })) )
6. Создать селектор
ng g selector store/selectors/counter --skipTests
импортировать { createFeatureSelector, createSelector } из "@ngrx/store" импортировать { counterFeatureKey, State } из "../reducers/counter.reducer" импортировать { AppState } из ".." экспортировать const selectCounter = createFeatureSelector<AppState, State>(counterFeatureKey) экспортировать const selectCount = createSelector(selectCounter, state => state.count)
7. Класс компонента запускает действие и получает статус.
импортировать {выбрать, Магазин} из "@ngrx/store" импортировать { Observable } из "rxjs" импортировать { AppState } из "./store" импортировать {уменьшить, увеличить} из "./store/actions/counter.actions" импортировать { selectCount } из "./store/selectors/counter.selectors" класс экспорта AppComponent { количество: Наблюдаемый<число> конструктор (частный магазин: Store<AppState>) { this.count = this.store.pipe(select(selectCount)) } приращение() { this.store.dispatch(increment()) } декремент() { this.store.dispatch(декремент()) } }
8. Статус отображения шаблона компонента
<button (click)="increment()">+</button> <span>{{ count | асинхронный }}</span> <button (click)="decrement()">-</button>
1. Используйте диспетчеризацию в компоненте для передачи параметров при запуске действия, и в конечном итоге параметры будут помещены в объект действия.
this.store.dispatch(increment({ count: 5 }))
2. При создании функции Action Creator получите параметры и укажите тип параметра.
импортировать { createAction, props } из "@ngrx/store" экспорт константного приращения = createAction("increment", props<{ count: Number }>())
функция экспорта объявления props<P расширяет объект>(): Props<P>;
3. Получите параметры через объект Action в Редюсере.
экспортировать константный редуктор = createReducer( начальное состояние, on(increment, (state, action) => ({ count: state.count + action.count })) )
MetaReducer — это связующее звено между Action -> Редюсером, позволяющее разработчикам предварительно обрабатывать действие (вызываемое перед вызовами обычных функций Редюсера).
функция отладки (редуктор: ActionReducer<любой>): ActionReducer<любой> { возвращаемая функция (состояние, действие) { возврат редуктора (состояние, действие) } } экспортировать константные метаредюсеры: MetaReducer<AppState>[] = !environment.production ?[отлаживать] : []
Требование: добавьте кнопку на страницу. После нажатия кнопки подождите одну секунду, чтобы значение увеличилось.
1. Добавьте кнопку асинхронного увеличения значения в шаблоне компонента. После нажатия кнопки выполняется метод increment_async
.
<button (click)="increment_async()">асинхронный</button>
2. Добавьте метод increment_async
в класс компонента и запустите действие для выполнения асинхронных операций в этом методе.
приращение_async() { this.store.dispatch(increment_async()) }
3. Добавьте действие для выполнения асинхронных операций в файле действий.
экспортировать const инкремент_async = createAction("increment_async")
4. Создайте Эффект, получите Действие и выполните побочные эффекты и продолжайте запускать Действие.
ng g effect store/effects/counter --root --module app.module.ts --skipTests
Функция Effect предоставляется модулем @ngrx/effects, поэтому соответствующие зависимости модуля необходимо импортировать в корневой модуль.
import { Injectable } из "@angular/core" импортировать { Actions, createEffect, ofType } из "@ngrx/effects" import { инкремент, инкремент_async } из "../actions/counter.actions" импортировать { mergeMap, map } из "rxjs/operators" импортировать {таймер} из "rxjs" // создатьЭффект // Используется для создания эффекта. Эффект используется для выполнения побочных эффектов. // Передаем функцию обратного вызова при вызове метода и возвращаем объект Observable в функции обратного вызова. Объект Action, который будет запущен после выполнения побочных эффектов. // Возвращаемое значение функции обратного вызова продолжает возвращаться внутри createEffect. метод, а окончательное возвращаемое значение сохраняется в свойствах класса Effect // После создания экземпляра класса Effect NgRx подпишется на свойства класса Effect. Когда побочные эффекты будут завершены, он получит объект Action, который будет запущен. и запустить действие. //Действия // Когда компонент запускает действие, эффект должен получить действие через службу действий, поэтому в классе эффекта объект экземпляра класса службы действий вводится в класс эффекта через параметр конструктора. Объект класса обслуживания Actions — Observable Object, при запуске Action сам объект Action будет создан как поток данных // ofType. // Фильтруем целевой объект Action. // Параметром является функция Action Creator целевого Action // Если целевой объект Action не отфильтрован, поток данных не будет продолжать отправляться на этот раз // Если целевой объект Action отфильтрован, объект Action будет продолжать отправляться в виде потока данных @Injectable() класс экспорта CounterEffects { конструктор (частные действия: Действия) { // this.loadCount.subscribe(console.log) } loadCount = createEffect(() => { верните this.actions.pipe( ofType(increment_async), mergeMap(() => timer(1000).pipe(map(() => приращение({ count: 10 })))) ) }) }
1. Обзор
Entity переводится как сущность, а сущность — это часть данных в коллекции.
NgRx предоставляет объекты адаптера объекта. В объектах адаптера объекта предусмотрены различные методы управления объектами в коллекции. Целью является повышение эффективности работы разработчиков с объектами.
2. Ядро
1. EntityState: интерфейс типа сущности.
/* { идентификаторы: [1, 2], сущности: { 1: { id: 1, title: «Привет, Angular» }, 2: { id: 2, title: «Привет, NgRx» } } } */ Состояние интерфейса экспорта расширяет EntityState<Todo> {}
2. createEntityAdapter: создать объект адаптера сущности.
3. EntityAdapter: интерфейс типа объекта адаптера сущности.
экспортировать константный адаптер: EntityAdapter<Todo> = createEntityAdapter<Todo>() // Получить начальное состояние. Вы можете передавать параметры объекта или нет. // {ids: [],entities: {}} экспортировать const InitialState: State = адаптер.getInitialState()
3. Метод экземпляра
https://ngrx.io/guide/entity/adapter#adapter-collection-methods
4. Селектор
// selectTotal получает количество элементов данных // selectAll получает все данные и представляет их в виде массива // selectEntities получает коллекцию сущностей и представляет ее в виде словаря // selectIds получает коллекцию идентификаторов и представляет это в виде массива const { selectIds, selectEntities, selectAll, selectTotal } = адаптер .getSelectors();
экспортировать const selectTodo = createFeatureSelector<AppState, State>(todoFeatureKey) экспортировать const selectTodos = createSelector(selectTodo, selectAll)
1. Синхронизировать статус маршрутизации
1)Введение модулей
импортировать { StoreRouterConnectingModule } из "@ngrx/router-store" @NgModule({ импорт: [ StoreRouterConnectingModule.forRoot() ] }) класс экспорта AppModule {}
2) Интегрируйте статус маршрутизации в магазин.
импортировать * как fromRouter из "@ngrx/router-store" интерфейс экспорта AppState { маршрутизатор: fromRouter.RouterReducerState } экспортировать константные редукторы: ActionReducerMap<AppState> = { маршрутизатор: fromRouter.routerReducer }
2. Создайте селектор для получения статуса маршрутизации.
// router.selectors.ts импортировать { createFeatureSelector } из "@ngrx/store" импортировать { AppState } из ".." импортировать { RouterReducerState, getSelectors } из "@ngrx/router-store" const selectRouter = createFeatureSelector<AppState, RouterReducerState>( "маршрутизатор" ) экспортировать константу { // Получаем информацию, относящуюся к текущему маршруту (параметры маршрутизации, конфигурация маршрутизации и т. д.) выберите текущий маршрут, // Получаем содержимое после номера # в адресной строке selectFragment, // Получаем параметры запроса маршрутизации selectQueryParams, // Получаем конкретный параметр запроса selectQueryParam('name') выберитеQueryParam, // Получаем параметры динамической маршрутизации selectRouteParams, // Получаем определенный параметр динамической маршрутизации selectRouteParam('name') выберитеПараметрМаршрута, // Получаем пользовательские данные маршрута selectRouteData, // Получаем фактический адрес доступа к маршруту selectUrl } = getSelectors(selectRouter)
// домашний.компонент.ц импортировать {выбрать, Магазин} из "@ngrx/store" импортируйте {AppState} из "src/app/store" импортировать { selectQueryParams } из "src/app/store/selectors/router.selectors" класс экспорта AboutComponent { конструктор (частный магазин: Store<AppState>) { this.store.pipe(select(selectQueryParams)).subscribe(console.log) } }