Эта статья даст вам более глубокое понимание менеджера состояний 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)
}
}