簡體   English   中英

NgRx/Effects 不觸發 Reducer

[英]NgRx/Effects not triggering the Reducer

我知道問題的標題含糊不清,但不幸的是我不完全知道是什么導致了我的問題,所以請耐心等待。

我剛剛開始處理一個小的 Angular 8 任務,它也使用 NgRx/Store 和 NgRx/Effects。 我正在使用getBooks函數獲取一組Book對象。 我的代碼如下(沒有把輸入端口放在任何地方只是為了使代碼部分更短)

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

書.service.ts

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

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

  getBooks(){
      return booksData;
  }
}

booksData是我從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; }[]'.

另外,我添加了StoreModule.forRoot({ books: reducer})EffectsModule.forRoot([BooksEffects])imports並將BookService添加到app.module.ts 中的Providers

您的代碼中有兩個錯誤。

MergeMap 使用不當

您的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 })                
   )
);

為了詳細說明這一點,當您想從一個 Observable 切換到另一個 Observable 時使用mergeMapswitchMap )。 回調應該返回一個 Observable,然后mergeMap可以訂閱它。 map的回調預計會返回一個值並將該值包裝到一個新的 Observable 中。 當您getBooks()不返回 Observable 時, mergeMap無法訂閱它,TypeScript 知道這一點並拋出所述錯誤。 或者,您也可以更改getBooks()以返回一個 Observable(如果您以后想從 HTTP 請求中獲取這些,這將是一個方法,這將返回一個 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()返回一個普通的數組。

所以要么不要在結果數組上調用pipe要么讓你的服務返回一個Observable 一個簡單的方法是返回of( booksData) ; of函數從給定的值創建一個Observable

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM