NgRx /效果未触发减速器

时间:2019-12-20 14:14:20

标签: angular typescript angular8 ngrx-store ngrx-effects

我知道问题的标题含糊,但不幸的是,我不完全知道是什么原因导致了我的问题,所以请耐心等待。

我刚刚开始处理一个小的Angular 8任务,该任务也使用NgRx / Store和NgRx / Effects。我正在使用Book函数获取getBooks对象的数组。我的代码如下(没有为了使代码部分更短而在所有地方都插入了端口)

book.component.ts

export class BookComponent {

  constructor(private booksService: BooksService, public store: Store<BooksState>) {
    this.books$ = store.pipe(select('books'));
  }

  books$: Observable<BooksState>;
  BooksSubscription: Subscription;
  booksList: Book[];

  ngOnInit() {
    this.BooksSubscription = this.books$
      .pipe( map(x => { this.booksList = x.Books; }) ).subscribe();
    this.store.dispatch(BooksActions.BeginGetBooksAction())
  }
}

book.service.ts

import { Injectable } from '@angular/core';
import booksData from "../../books.json";

@Injectable()
export class BooksService {
  constructor() { }

  getBooks(){
      return booksData;
  }
}

booksDataBook文件导入的json类型对象的数组。

book.action.ts

import { createAction, props } from "@ngrx/store";
import { Book } from "./book";

export const GetBooksAction = createAction("GetBooks");
export const BeginGetBooksAction = createAction("BeginGetBooks");
export const SuccessGetBooksAction = createAction( "SuccessGetBooks", props<{ payload: Book[] }>());

book.reducer.ts

import { Action, createReducer, on } from "@ngrx/store";
import * as BooksActions from "./book.action";
import { Book } from "./book";

export interface BooksState {
  Books: Book[];
}

const initialState: BooksState = {
    Books: []
};

const booksReducer = createReducer(
    initialState,
    on(BooksActions.GetBooksAction, state => state))
    on(BooksActions.SuccessGetBooksAction, (state: BooksState, { payload }) => {
      console.log(payload)
      return { ...state, Books: payload };
    });

  export function reducer(state: BooksState | undefined, action: Action) {
    return booksReducer(state, action);
  }

book.effect.ts

现在这是我迷路的地方。我在NgRx文档上找到了参考代码,基于该参考代码我编写了代码,但是它不起作用

import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Action } from '@ngrx/store';
import { Observable } from 'rxjs';
import { map, mergeMap} from 'rxjs/operators';
import * as BooksActions from './book.action';
import { Book } from './book';
import { BooksService } from './book.service';


@Injectable()
export class BooksEffects {
    constructor(private action$: Actions, private booksService: BooksService) { }

     GetBooks$: Observable<Action> = createEffect(() =>
        this.action$.pipe(
            ofType(BooksActions.BeginGetBooksAction),
            mergeMap(
                () => this.booksService.getBooks().pipe(
                    map((booksData: Book[]) => {
                        return BooksActions.SuccessGetBooksAction({ payload: booksData });
                    }))
            )
        )
    )
  );
}

在编译过程中出现以下错误。错误出现在我有pipe functions

的行上
error TS2322: Type 'Observable<unknown>' is not assignable to type 'Observable<Action> | ((...args: any[]) 
=> Observable<Action>)'.
      Type 'Observable<unknown>' is not assignable to type 'Observable<Action>'.
        Property 'type' is missing in type '{}' but required in type 'Action'.

error TS2339: Property 'pipe' does not exist on type '{ "isbn": string; "title": string; "subtitle": string; "author": string; "published": string; "publisher": string; "pages": number; "description": string; "website": string; }[]'.

此外,我在 app.module.ts StoreModule.forRoot({ books: reducer})和EffectsModule.forRoot([BooksEffects])添加到了imports,并将BookService添加到了Providers >

2 个答案:

答案 0 :(得分:3)

您的代码中有两个错误。

合并地图使用不正确

您的this.booksService.getBooks()似乎不返回Observable。在这种情况下,您要使用map而不是mergeMap

GetBooks$: Observable<Action> = createEffect(() =>
   this.action$.pipe(
      ofType(BooksActions.BeginGetBooksAction),
      map(() => this.booksService.getBooks()),
      map(payload => BooksActions.SuccessGetBooksAction({ payload })                
   )
);

为了对此进行详细说明,当您要从一个可观察对象切换到另一个(类似mergeMap)时,使用switchMap。回调应返回mergeMap可以随后订阅的Observable。 map的回调应返回一个值,并将该值包装到一个新的Observable中。由于您getBooks()不返回Observable,mergeMap无法订阅它,因此TypeScript知道这一点并抛出错误。 另外,您也可以将getBooks()更改为返回一个Observable(如果您以后想从HTTP Request中获取这些内容,则返回Observable。这是方法)。

减速器中的括号错误

此外,在进一步检查中,您的效果器和减速器实际上正在运行。但是,在减速器中,您的偏瘫有一个小错误。看这个:

const booksReducer = createReducer(
    initialState,
    on(BooksActions.GetBooksAction, state => state))  // <---- This ")" is closing your "createReducer" function!
    on(BooksActions.SuccessGetBooksAction, (state: BooksState, { payload }) => {
      console.log(payload)
      return { ...state, Books: payload };
    });

因此,如果您格式化此格式以反映其功能,则您会写:

const booksReducer = createReducer(
    initialState,
    on(BooksActions.GetBooksAction, state => state)
)

// You "on" function is actually outside "createReducer" effectively NEVER being triggered (but this is syntactically correct so a very tricky error)
on(BooksActions.SuccessGetBooksAction, (state: BooksState, { payload }) => {
   console.log(payload)
   return { ...state, Books: payload };
});

所以您只需要解决该问题:

const booksReducer = createReducer(
    initialState,
    on(BooksActions.GetBooksAction, state => state),
    on(BooksActions.SuccessGetBooksAction, (state: any, { payload }) => {
      console.log('Reducer is running, value is:', payload)
      return { ...state, Books: payload };
    })
);

这里是工作中的Stackblitz。查看控制台以查看所有被触发的内容。

答案 1 :(得分:1)

pipeObservable的函数,但是this.booksService.getBooks()返回一个纯数组。

因此,不要在生成的数组上调用pipe,或者让您的服务返回Observable。一种简单的方法是返回of( booksData); of函数根据给定的值创建一个Observable