我知道问题的标题含糊,但不幸的是,我不完全知道是什么原因导致了我的问题,所以请耐心等待。
我刚刚开始处理一个小的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;
}
}
booksData
是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; }[]'.
此外,我在 app.module.ts StoreModule.forRoot({ books: reducer})和EffectsModule.forRoot([BooksEffects])
添加到了imports
,并将BookService
添加到了Providers
>
答案 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)
pipe
是Observable
的函数,但是this.booksService.getBooks()
返回一个纯数组。
因此,不要在生成的数组上调用pipe
,或者让您的服务返回Observable
。一种简单的方法是返回of(
booksData)
; of
函数根据给定的值创建一个Observable
。