[英]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 時使用mergeMap
( switchMap
)。 回調應該返回一個 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 。 查看控制台以查看正在觸發的所有內容。
pipe
是Observable
一個函數,但是this.booksService.getBooks()
返回一個普通的數組。
所以要么不要在結果數組上調用pipe
要么讓你的服務返回一個Observable
。 一個簡單的方法是返回of( booksData)
; of
函數從給定的值創建一個Observable
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.