Redux-observable中fetch后派发两个动作报错求助
嘿,这个问题我太熟了!你遇到的Uncaught Error: Actions must be plain objects错误,核心原因是Redux的默认Store只能处理普通JavaScript对象类型的Action——而你返回的是包含两个Action的Observable流,这属于异步/多Action的复杂逻辑,必须用对应的中间件来处理才行!
为什么会报错?
Redux的核心原则之一是:Action必须是普通对象(比如{ type: 'XXX', payload: ... })。当你直接返回Observable或者函数这类非普通对象时,Store不知道该怎么处理,就会抛出这个错误。刚好你提到了Observable,那redux-observable就是专门用来处理这类基于RxJS的异步Action流的中间件,咱们就从这个方案入手。
方案一:用redux-observable处理Observable流
第一步:安装并配置中间件
首先确保你已经安装了依赖:
npm install redux-observable rxjs
然后配置你的Redux Store,把redux-observable中间件加进去:
import { createStore, applyMiddleware } from 'redux'; import { createEpicMiddleware } from 'redux-observable'; import rootReducer from './reducers'; import rootEpic from './epics'; // 后面会写这个文件 // 创建epic中间件实例 const epicMiddleware = createEpicMiddleware(); // 初始化Store,应用中间件 const store = createStore( rootReducer, applyMiddleware(epicMiddleware) ); // 运行根Epic epicMiddleware.run(rootEpic); export default store;
第二步:编写处理逻辑的Epic
Epic是redux-observable的核心,它会监听特定的Action,然后返回一个Action流(比如你需要的先派发token成功、再派发数据成功的两个Action)。
先定义你的Action类型和Creator:
// actionTypes.js export const FETCH_INIT = 'FETCH_INIT'; export const TOKEN_SUCCESS = 'TOKEN_SUCCESS'; export const DATA_SUCCESS = 'DATA_SUCCESS'; // actionCreators.js import { FETCH_INIT, TOKEN_SUCCESS, DATA_SUCCESS } from './actionTypes'; export const fetchInit = () => ({ type: FETCH_INIT }); export const tokenSuccess = (token) => ({ type: TOKEN_SUCCESS, payload: token }); export const dataSuccess = (data) => ({ type: DATA_SUCCESS, payload: data });
然后编写处理异步逻辑的Epic:
// epics.js import { combineEpics } from 'redux-observable'; import { mergeMap, map } from 'rxjs/operators'; import { FETCH_INIT } from './actionTypes'; import { tokenSuccess, dataSuccess } from './actionCreators'; // 监听FETCH_INIT Action,执行异步流 const fetchDataEpic = (action$) => action$.ofType(FETCH_INIT) .pipe( mergeMap(() => // 第一步:请求token fetch('/api/get-token') .then(res => res.json()) .then(tokenData => tokenData.token) // 先派发token成功的Action .map(token => tokenSuccess(token)) // 接着用token请求数据,派发数据成功的Action .pipe( mergeMap(token => fetch(`/api/get-data?token=${token}`) .then(res => res.json()) .map(data => dataSuccess(data)) ) ) ) ); // 合并所有Epic(如果只有这一个,也可以直接导出fetchDataEpic) export default combineEpics(fetchDataEpic);
最后,你只需要在组件里派发fetchInit()这个Action,redux-observable就会自动处理后续的两个异步Action派发了。
方案二:用redux-thunk实现多次派发(备选)
如果你不想用RxJS和redux-observable,redux-thunk也是个简单的选择——它允许Action Creator返回一个函数,在函数里你可以多次调用dispatch。
第一步:安装并配置中间件
npm install redux-thunk
配置Store:
import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './reducers'; const store = createStore( rootReducer, applyMiddleware(thunk) ); export default store;
第二步:编写Thunk Action Creator
import { tokenSuccess, dataSuccess } from './actionCreators'; export const fetchData = () => async (dispatch) => { try { // 第一步:获取token并派发Action const tokenRes = await fetch('/api/get-token'); const tokenData = await tokenRes.json(); dispatch(tokenSuccess(tokenData.token)); // 第二步:用token获取数据并派发Action const dataRes = await fetch(`/api/get-data?token=${tokenData.token}`); const data = await dataRes.json(); dispatch(dataSuccess(data)); } catch (err) { // 这里可以加错误处理,比如派发一个错误Action console.error('请求失败:', err); } };
这样在组件里调用dispatch(fetchData()),就能依次完成两个Action的派发了。
内容的提问来源于stack exchange,提问作者AlxVallejo

