Angular 15中创建NgRx Effect时抛出TypeError: undefined不是非空对象
NgRx Effect 运行报错 TypeError: undefined is not a non-null object
我正在学习Angular 15,编写了一个可注入类创建NgRx Effect,用于和Firebase数据库交互存储数据,但运行时抛出TypeError: undefined is not a non-null object错误。相关代码如下:
constructor(private actions$: Actions, private http: HttpClient) {} fetchRecipes = createEffect((): any => { this.actions$.pipe( ofType(RecipesActions.FETCH_RECIPES), switchMap(() => { return this.http.get<Recipe[]>( 'https://recipebook-re-default-rtdb.europe-west1.firebasedatabase.app/recipes.json', ) }), map(recipes => { return recipes.map(recipe => { return { ...recipe, ingredients: recipe.ingredients ? recipe.ingredients : [] }; }); }), map(recipes => { return new RecipesActions.SetRecipes(recipes); }) ); });
我是Angular新手,代码跟着课程编写,推测可能是课程内容过时存在废弃用法,但找不到问题所在。代码托管在GitHub仓库中(StackBlitz链接无法正常使用)。
问题定位与修复
1. Effect 未返回 Observable
你的createEffect回调函数没有返回this.actions$.pipe(...)的结果,导致Effect无法生成有效的Observable,这是触发错误的核心原因。只需添加return关键字即可修复:
fetchRecipes = createEffect((): any => { // 新增return,返回Observable流 return this.actions$.pipe( ofType(RecipesActions.FETCH_RECIPES), switchMap(() => { return this.http.get<Recipe[]>( 'https://recipebook-re-default-rtdb.europe-west1.firebasedatabase.app/recipes.json', ) }), map(recipes => { return recipes.map(recipe => { return { ...recipe, ingredients: recipe.ingredients ? recipe.ingredients : [] }; }); }), map(recipes => { return new RecipesActions.SetRecipes(recipes); }) ); });
2. 处理HTTP请求返回null的场景
Firebase实时数据库在没有数据时会返回null,而非空数组。直接对null调用map方法会引发错误,需要先判断recipes是否存在:
map(recipes => { // 若recipes为null/undefined,默认转为空数组 return (recipes || []).map(recipe => { return { ...recipe, ingredients: recipe.ingredients ?? [] // 可选:用空值合并运算符替代三元表达式 }; }); }),
3. 替换过时的类式Action(建议)
当前NgRx版本推荐使用函数式Action,课程中的类式Action写法已逐渐废弃。可以按如下方式重构:
// 定义函数式Action export const setRecipes = createAction( '[Recipes] Set Recipes', props<{ recipes: Recipe[] }>() ); // 在Effect中调用 map(recipes => { return setRecipes({ recipes }); }),
4. 优化类型定义(建议)
避免使用any作为返回类型,明确指定Effect的Observable类型,提升代码可维护性:
import { createAction, props } from '@ngrx/store'; import { Observable } from 'rxjs'; // 先定义函数式Action export const setRecipes = createAction( '[Recipes] Set Recipes', props<{ recipes: Recipe[] }>() ); // 指定Effect返回类型 fetchRecipes = createEffect((): Observable<ReturnType<typeof setRecipes>> => { return this.actions$.pipe( // ... 其余逻辑 ); });
内容的提问来源于stack exchange,提问作者DanieleManna
相关产品推荐
相关产品推荐

