NgRX store select returns 存储状态而不是数据
NgRX store select returns store state instead of data
我正在尝试将 ngrx v4 实施到我的 angular 项目中,并努力从 ngrx 存储中获取数据。我根据 github page 上提供的 api 文档编写了 Actions、Reducer 和 Effects,在我看来一切都是正确的,但我得到的存储状态不是数据,而是这样的:
所以,如果有人能帮助我找出我的错误所在,我将不胜感激。提前致谢。我的代码如下
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 {}
因为您正在使用 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'} }))
);
这不是对 antonyboom 特定问题的回答,而是对根据问题标题来到这里的其他人的有用提示:NGRX 的 Store.select 似乎将 return将 observable 存储为默认值,以防它无法在您查询的路径中找到数据。认为 Apache 404 错误。
我不得不修改我的类型转换以确保打字稿没有强制执行不正确的存储结构。具体来说,请注意,为减速器中的第一个参数指定的接口与注入组件的接口不同。
型号、减速器:
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);
}
...
}
reducer 导入部分提供的名称必须与 State
的参数名称相同
商店:
export interface AppState {
logs: string[];
}
export interface AppStore{
appState: AppState; // (1)
}
app.module.ts 导入:
StoreModule.forRoot({
appState: reducerFunction // (2)
})
因此,(1) 和 (2) (appState
) 必须相同。
我正在尝试将 ngrx v4 实施到我的 angular 项目中,并努力从 ngrx 存储中获取数据。我根据 github page 上提供的 api 文档编写了 Actions、Reducer 和 Effects,在我看来一切都是正确的,但我得到的存储状态不是数据,而是这样的:
所以,如果有人能帮助我找出我的错误所在,我将不胜感激。提前致谢。我的代码如下
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 {}
因为您正在使用 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'} })) );
这不是对 antonyboom 特定问题的回答,而是对根据问题标题来到这里的其他人的有用提示:NGRX 的 Store.select 似乎将 return将 observable 存储为默认值,以防它无法在您查询的路径中找到数据。认为 Apache 404 错误。
我不得不修改我的类型转换以确保打字稿没有强制执行不正确的存储结构。具体来说,请注意,为减速器中的第一个参数指定的接口与注入组件的接口不同。
型号、减速器:
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);
}
...
}
reducer 导入部分提供的名称必须与 State
商店:
export interface AppState {
logs: string[];
}
export interface AppStore{
appState: AppState; // (1)
}
app.module.ts 导入:
StoreModule.forRoot({
appState: reducerFunction // (2)
})
因此,(1) 和 (2) (appState
) 必须相同。