redux-observable中concatMap用async fetch无法返回多action问题
问题原因
Redux Observable 中间件的核心逻辑是接收epic返回的动作流,将流中发射的每个单独值作为action分发给Redux。出现这个报错的核心原因是:
- 你在
concatMap中使用了async函数,这类函数的返回值会被自动包装为Promise - RxJS的
concatMap处理Promise类型返回值时,只会将Promise resolve的最终结果作为单个值发射到流中,不会自动展开数组内的元素 - 你直接返回action数组时,整个数组会被当作单个"action"传给Redux,而Redux要求action必须是普通平面对象,数组不符合要求,因此抛出校验错误。
返回单个action时因为值本身就是符合要求的普通对象,所以可以正常运行。
修复方法
最简便的修复方式是使用RxJS内置的of操作符,将需要分发的多个action包装为会逐个发射值的Observable,concatMap会自动订阅这个Observable,把里面的每个action单独分发出去:
- 首先从rxjs导入
of方法 - 原本返回单个action、返回数组的位置,都改为返回
of(...待分发的action列表)
修正后的核心代码如下:
import { of } from 'rxjs'; import { fetchCharactersAction, setCharactersList, setError } from 'models/actions/characterActions'; import { ofType } from 'redux-observable'; import { concatMap, catchError } from 'rxjs/operators'; const fetchCharactersEpic = action$ => action$.pipe( ofType(fetchCharactersAction.type), concatMap(async ({ payload: { name, status, gender, page } }) => { const url = `${process.env.REACT_APP_RICKANDMORTY}/character?page=${page}&name=${name}&status=${status}&gender=${gender}`; const characters = await fetch(url); const returnedCharacters = await characters.json(); if (returnedCharacters?.error === '' || !returnedCharacters?.error) { // 多action直接作为of的参数传入即可,支持任意数量 return of( setCharactersList(returnedCharacters), // 其他需要同步分发的action按顺序写在这里即可,比如action2(), action3() ); } return of(setError(returnedCharacters?.error)); }), // 建议补充错误捕获,避免请求异常时整个epic终止 catchError(async (err) => of(setError(err.message))) );
如果不想使用of包装,也可以把async/await改写为Promise链式调用,在then中返回数组——但这种写法可读性更差,不推荐。
补充说明:如果
concatMap的回调不是async函数、直接返回action数组,RxJS会自动将数组转为逐个发射元素的Observable,不会出现这个问题,但async函数返回Promise包裹数组的场景下不会触发这个自动转换逻辑。
内容的提问来源于stack exchange,提问作者Vaios Anastasiadis
相关产品推荐
相关产品推荐

