2017-09-02 54 views
0

我使用了ngRx文檔中一組非常有用的示例,嘗試着手使用我們的Angular應用程序的redux模型。下面的代碼工作 - 所有操作正確地觸發並更新商店。我可以在redux開發工具和商店記錄器中看到它們。ngRx/store在Angular模板中沒有顯示可觀察值

但是,我無法得到任何東西顯示在模板中。這只是空白。我不確定它是否涉及到三層的州樹,看起來像這樣的:

grandpa: { 
    grandpa: { 
    grandpaCounter: 50 
    } 
} 

我曾試圖按照NGRX example-app我使用的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

ngrx的版本是什麼? –

+0

@RahulSingh ngrx 4 –

回答

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()) 
    } 
}