我正在使用来自ngRx
文档的一组非常人为的例子来尝试开始使用我们的Angular应用程序的redux模型。下面的代码有效 - 所有操作都会正确触发并更新商店。我可以在redux dev工具和商店记录器中看到它们。
但是,我无法在模板中显示任何内容。它只是空白。我不确定它是否与状态树的三层相关,如下所示:
grandpa: {
grandpa: {
grandpaCounter: 50
}
}
我尝试使用example-app
来关注ngRx reselect
,但也许我在滥用这些选择器?我还能错过什么?
app.component.html
<button (click)="increment()">Increment</button>
<button (click)="decrement()">Decrement</button>
<div>Current Count: {{ grandpaCounter$ | async }}</div>
<button (click)="resetCounter()">Reset Counter</button>
app.module.ts
// Native angular modules
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser' /* Registers critical application service providers */
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { HttpClientModule } from '@angular/common/http'
// Bootstrap component
import { AppComponent } from './app.component'
// ngRx
import { StoreModule } from '@ngrx/store'
import { StoreDevtoolsModule } from '@ngrx/store-devtools'
import { EffectsModule } from '@ngrx/effects'
import {
StoreRouterConnectingModule,
routerReducer as router
} from '@ngrx/router-store'
// Router
import { AppRoutingModule } from './app.routing'
// Shared module
import { SharedModule } from './shared/shared.module'
// Functional modules
import { GrandpaModule } from './modules/grandpa/grandpa.module'
// ngRx store middleware
import { metaReducers } from './app.store'
// Configuration
import { APP_CONFIG, AppConfig } from './app.config'
@NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule,
StoreModule.forRoot({ router: router }, { metaReducers }),
StoreRouterConnectingModule,
StoreDevtoolsModule.instrument({
maxAge: 25 // Retains last 25 states
}),
EffectsModule.forRoot([]),
HttpClientModule,
SharedModule,
GrandpaModule,
AppRoutingModule // must be last
],
declarations: [AppComponent],
providers: [{ provide: APP_CONFIG, useValue: AppConfig }],
bootstrap: [AppComponent]
})
export class AppModule {}
app.store.ts
// ngRx
import { ActionReducer, MetaReducer } from '@ngrx/store'
import { storeLogger } from 'ngrx-store-logger'
// Root state
export interface State {}
/* Meta-reducers */
export function logger(reducer: ActionReducer<State>): any {
// default, no options
return storeLogger()(reducer)
}
export const metaReducers = process.env.ENV === 'production' ? [] : [logger]
grandpa.module.ts
// Native angular modules
import { NgModule } from '@angular/core'
// ngRx
import { StoreModule } from '@ngrx/store'
// Shared module
import { SharedModule } from '../../shared/shared.module'
// Functional Components
import { GrandpaComponent } from './grandpa.component'
// Router
import { GrandpaRoutingModule } from './grandpa.routing'
// Store
import { branchReducers } from './grandpa.store'
@NgModule({
imports: [
StoreModule.forFeature('grandpa', branchReducers),
SharedModule,
GrandpaRoutingModule // must be last
],
declarations: [GrandpaComponent]
})
export class GrandpaModule {}
grandpa.store.ts
// ngRx
import { ActionReducerMap, createSelector } from '@ngrx/store'
// Module branch reducers
import * as grandpaReducer from './grandpa.reducer'
// Feature state
export interface State {
grandpa: grandpaReducer.State
}
// Feature reducers map
export const branchReducers: ActionReducerMap<State> = {
grandpa: grandpaReducer.reducer
}
// Module selectors
export const getGrandpaState = (state: State) => state.grandpa
export const getGrandpaCounter = createSelector(
getGrandpaState,
grandpaReducer.getGrandpaCounter
)
grandpa.reducer.ts
import { createSelector } from '@ngrx/store'
import * as GrandpaActions from './grandpa.actions'
import * as grandpaStore from './grandpa.store'
export interface State {
grandpaCounter: number
}
export const initialState: State = {
grandpaCounter: 50
}
export function reducer(state = initialState, action: GrandpaActions.Actions) {
switch (action.type) {
case GrandpaActions.INCREMENT:
return { grandpaCounter: state.grandpaCounter + 1 }
case GrandpaActions.DECREMENT:
return { grandpaCounter: state.grandpaCounter - 1 }
case GrandpaActions.RESET_COUNTER:
return { grandpaCounter: initialState.grandpaCounter }
default:
return { grandpaCounter: state.grandpaCounter }
}
}
// Selectors
export const getGrandpaCounter = (state: State) => state.grandpaCounter
grandpa.component.ts
import { Component } from '@angular/core'
import { Observable } from 'rxjs/Observable'
import { Store } from '@ngrx/store'
import * as GrandpaActions from './grandpa.actions'
import * as grandpaStore from './grandpa.store'
@Component({
selector: 'portal-grandpa',
templateUrl: './grandpa.component.html'
})
export class GrandpaComponent {
grandpaCounter$: Observable<number>
constructor(private store: Store<grandpaStore.State>) {
this.grandpaCounter$ = store.select(grandpaStore.getGrandpaCounter)
}
increment() {
this.store.dispatch(new GrandpaActions.Increment())
}
decrement() {
this.store.dispatch(new GrandpaActions.Decrement())
}
resetCounter() {
this.store.dispatch(new GrandpaActions.ResetCounter())
}
}
答案 0 :(得分:0)
它最终成为州树和选择者。我需要将我的选择器切片定义为三个状态级别:
<强> grandpa.store.ts 强>
// ngRx
import {
ActionReducerMap,
createSelector,
createFeatureSelector
} from '@ngrx/store'
// Branch reducers
import * as grandpaReducer from './grandpa.reducer'
// State
export interface State {
grandpa: grandpaReducer.State
}
// Reducers map
export const branchReducers: ActionReducerMap<State> = {
grandpa: grandpaReducer.reducer
}
// Selectors
export const getS0 = createFeatureSelector<State>('grandpa')
export const getS1 = (state: State) => state.grandpa
export const getS01 = createSelector(getS0, getS1)
export const getS2 = createSelector(getS01, grandpaReducer.getGrandpaCounter)
<强> grandpa.component.ts 强>
import { Component } from '@angular/core'
import { Observable } from 'rxjs/Observable'
import { Store } from '@ngrx/store'
import * as GrandpaActions from './grandpa.actions'
import * as grandpaStore from './grandpa.store'
@Component({
selector: 'portal-grandpa',
templateUrl: './grandpa.component.html'
})
export class GrandpaComponent {
grandpaCounter$: Observable<number>
constructor(private store: Store<grandpaStore.State>) {
this.grandpaCounter$ = store.select(grandpaStore.getS2)
}
increment() {
this.store.dispatch(new GrandpaActions.Increment())
}
decrement() {
this.store.dispatch(new GrandpaActions.Decrement())
}
resetCounter() {
this.store.dispatch(new GrandpaActions.ResetCounter())
}
}
我仍然不确定为什么附加reducer状态及其直接选择器不起作用。我原本以为这个选择器可以使用它:
<强> grandpa.reducer.ts 强>
export const getGrandpaCounter = (state: State) => state.grandpaCounter
<强> grandpa.component.ts 强>
import { Component } from '@angular/core'
import { Observable } from 'rxjs/Observable'
import { Store } from '@ngrx/store'
import * as GrandpaActions from './grandpa.actions'
import * as grandpaReducer from './grandpa.reducer'
@Component({
selector: 'portal-grandpa',
templateUrl: './grandpa.component.html'
})
export class GrandpaComponent {
grandpaCounter$: Observable<number>
constructor(private store: Store<grandpaReducer.State>) {
this.grandpaCounter$ = store.select(grandpaReducer.getGrandpaCounter)
}
increment() {
this.store.dispatch(new GrandpaActions.Increment())
}
decrement() {
this.store.dispatch(new GrandpaActions.Decrement())
}
resetCounter() {
this.store.dispatch(new GrandpaActions.ResetCounter())
}
}