You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 05:20:48