NgRx/Effects 没有触发 Reducer

NgRx/Effects not triggering the Reducer

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

我刚开始做一个小的 Angular 8 任务,它也使用 NgRx/Store 和 NgRx/Effects。我正在使用 getBooks 函数获取 Book objects 的数组。我的代码如下(为了让代码部分更短,没有到处输入端口)

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;
  }
}

booksData 是 objects 类型的 Book 数组,我从 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; }[]'.

此外,我在imports中添加了StoreModule.forRoot({ books: reducer})EffectsModule.forRoot([BooksEffects]),在[=73=中添加了BookServiceProviders ]

你的代码有两个错误。

MergeMap 使用不当

你的 this.booksService.getBooks() 似乎不是 return Observable。在这种情况下,您想使用 map 而不是 mergeMap:

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

为了详细说明这一点,当你想从一个 Observable 切换到另一个时使用 mergeMap(类似于 switchMap)。回调预计 return 一个 Observable,然后 mergeMap 可以订阅。 map 的回调预计会 return 一个值并将该值包装到一个新的 Observable 中。由于您 getBooks() 没有 return Observable,mergeMap 无法订阅它,TypeScript 知道并抛出上述错误。 或者,您也可以将 getBooks() 更改为 return 一个 Observable(如果您稍后想从 HTTP 请求中获取这些,这将是 return 一个 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。查看控制台以查看触发的所有内容。

pipeObservable 的函数,但 this.booksService.getBooks() return 是一个普通数组。

因此,要么不要对生成的数组调用 pipe,要么让您的服务 return 成为 Observable。一个简单的方法是 return of( booksData); of 函数根据给定值创建一个 Observable