NgRX存储选择返回存储状态而不是数据

时间:2017-12-08 16:31:10

标签: angular ngrx ngrx-store

我正在尝试将ngrx v4实现到我的角度项目,并努力从ngrx商店获取数据。我根据github page上提供的api文档编写了Actions,Reducer和Effects,在我看来一切都是正确的,但我得到的存储状态不是数据:

enter image description here

所以我很感激有人可以帮助我弄清楚我的错误在哪里。提前致谢。我的代码在下面

interface.ts

export interface Category {
  id?: number;
  name: string;
  used: boolean;
}

actions.ts

import { Action } from '@ngrx/store';
import {Category} from '../categories';

export const GET_CATEGORIES  = '[Category] Get data';
export const GET_CATEGORIES_ERROR = '[Category] Get data error';
export const GET_CATEGORIES_SUCCESS  = '[Category] Get data success ';

export class GetCategories implements Action {
  readonly type = GET_CATEGORIES;
}
export class GetCategoriesError implements Action {
  readonly type = GET_CATEGORIES_ERROR;
}
export class GetCategoriesSuccess implements Action {
  readonly type = GET_CATEGORIES_SUCCESS;
  constructor(public payload: Category[]) { }
}

export type All = GetCategories | GetCategoriesSuccess | GetCategoriesError

reducer.ts

import * as CategoriesActions from './categories.actions';
import {Category} from '../categories';

export type Action = CategoriesActions.All;

export function categoriesReducer (state: Category[], action: Action) {

  switch (action.type) {

    case CategoriesActions.GET_CATEGORIES: {
      return state;
    }

    case CategoriesActions.GET_CATEGORIES_ERROR: {
      return state;
    }

    case CategoriesActions.GET_CATEGORIES_SUCCESS: {
      return action.payload;
    }

    default: {
      return state;
    }
  }
}

effects.ts

...
import {CategoriesService} from './categories.service';

@Injectable()
export class CategoriesEffects {

  @Effect() getCategories$: Observable<Action> = this.actions$
    .ofType('GET_CATEGORIES')
    .mergeMap(action => this.categoriesService.getCategories()
      .map(data => ({type: 'GET_CATEGORIES_SUCCESS', payload: data }))
      .catch(() => of({ type: 'GET_CATEGORIES_ERROR', payload: {message: 'Oops something is wrong'} }))
    );

  constructor(
    private actions$: Actions,
    private categoriesService: CategoriesService
  ) {}
}

component.ts

interface CategoryState {
  categories: Category[]
}

@Component({
  selector: 'app-categories',
  templateUrl: './categories.component.html',
  styleUrls: ['./categories.component.css'],
})

export class CategoriesComponent implements OnInit {

  categories$: Observable<Category[]>;

  constructor(private store: Store<CategoryState>) {

    console.log(this.categories$) // undefined

    this.categories$ = this.store.select('categories');

    console.log(this.categories$) // store state
  }

  ngOnInit() {
    this.getCategories()
  }

  getCategories () {
    this.store.dispatch({ type: 'GET_CATEGORIES' });
  } 
}

模块

@NgModule({
  imports: [
    ...
    StoreModule.forRoot({ categories: categoriesReducer }),
    EffectsModule.forRoot([CategoriesEffects]),
  ],
  declarations: [ CategoriesComponent ],
  providers:    [ CategoriesService ],
  entryComponents: []
})
export class CategoriesModule {}

3 个答案:

答案 0 :(得分:2)

这不是对antonyboom特定问题的回答,而是对根据问题标题到达此处的其他人的有用提示:看来NGRX的Store.select将会如果商店无法在您查询的路径中找到数据,则将商店视为默认值。认为Apache 404错误。

我必须修改我的类型转换以确保打字稿不会强制执行不正确的商店结构。具体来说,请注意,缩减器中第一个参数的接口指定与注入组件的参数不同。

Model,Reducer:

export interface AppState {
  textinput: string;
  integerVariable: number;
}
export interface State {
  app: AppState;
}

export function reducerFunction (
  state: AppState,
  action: Actions
) {
  switch (action.type) {
    ...
  }
}

app.module.ts:

StoreModule.forRoot({
  app: reducerFunction
})

app.component.ts

export class AppComponent {
constructor(private store: Store<State>) {
    this.currentSlide = store.select(s => s.app.textinput);
}
...
}

答案 1 :(得分:1)

由于您使用的是ngrx/store : 4.1

  • 您应该有一个reducer工厂将Reducer注入StoreModule

    import {ActionReducerMap} from '@ngrx/store';
    import {Category} from '../categories';
    import * as categoryReducer from './categories.reducer';
    
    export interface CategoryState {
      categories: Category[]
    }
    
    export interface AppStates {
      categoryState: CategoryState;
    }
    
    export const categoryReducers: ActionReducerMap<AppStates> = {
      categoryState: categoryReducer.reducer
    };
    
  • 使用reducer factory注入模块,如下所示

    StoreModule.forRoot(categoryReducers)
    import {categoryReducers} from './store/categories.reducer.factory';
    
  • 您的构造函数应将AppStates作为Store的类型

    constructor(private store: Store<AppStates>){}
    
  • 你的效果应该是

    @Effect() 
    getCategories$: Observable<Action> = this.actions$
        .ofType(CategoriesActions.GET_CATEGORIES)
        .mergeMap(action => this.categoriesService.getCategories()
              .map(data => ({type: CategoriesActions.GET_CATEGORIES_SUCCESS, payload: data }))
              .catch(() => of({ type: CategoriesActions.GET_CATEGORIES_ERROR, payload: {message: 'Oops something is wrong'} }))
        );
    

答案 2 :(得分:0)

减速器导入部分中提供的名称必须与State的参数名称相同

商店:

export interface AppState {
  logs: string[];
}

export interface AppStore{
  appState: AppState; // (1)
}

app.module.ts导入:

StoreModule.forRoot({
  appState: reducerFunction // (2)
})

因此(1)和(2)(appState)必须相同。