Redux-Saga中takeEvery与put触发无限循环,原因是什么?
Redux Saga无限循环:控制台重复打印'getInitList'
问题场景
运行Web应用时,控制台持续输出getInitList,应用陷入无限循环,相关代码如下:
import {takeEvery, put} from 'redux-saga/effects'; import {INIT_LIST_DATA} from './actionTypes' import "./actionTypes"; import axios from "axios"; function *getList() { console.log('getInitList') const res = yield axios.get('/todolist.json'); const data = res.data yield put({ type: INIT_LIST_DATA, value: data }) } // generator 函数 function *mySaga() { console.log('mySaga') yield takeEvery(INIT_LIST_DATA, getList) } export default mySaga;
原因分析
这是典型的循环触发闭环问题:
- 你用
takeEvery(INIT_LIST_DATA, getList)监听了INIT_LIST_DATA类型的action,只要这个action被派发,就会执行getList函数。 - 但
getList在获取数据后,又通过put派发了一个INIT_LIST_DATA类型的action。 - 这个新的action立刻被
takeEvery捕获,再次调用getList,如此反复就形成了无限循环,导致控制台不断打印getInitList。
修复方案
打破闭环的关键是把触发请求的action和更新数据的action分开:
- 先在
actionTypes.js里新增一个用于触发请求的action类型:
// actionTypes.js export const GET_INIT_LIST = 'get_init_list'; // 新增:触发请求的类型 export const INIT_LIST_DATA = 'init_list_data'; // 原:更新数据的类型
- 修改saga代码,让
takeEvery监听新增的GET_INIT_LIST,而getList完成请求后依然派发INIT_LIST_DATA来更新状态:
import {takeEvery, put} from 'redux-saga/effects'; import {GET_INIT_LIST, INIT_LIST_DATA} from './actionTypes' import axios from "axios"; function *getList() { console.log('getInitList') const res = yield axios.get('/todolist.json'); const data = res.data yield put({ type: INIT_LIST_DATA, value: data }) } function *mySaga() { console.log('mySaga') yield takeEvery(GET_INIT_LIST, getList) // 改为监听GET_INIT_LIST } export default mySaga;
- 之后在需要初始化列表数据的地方(比如组件挂载时),派发
GET_INIT_LIST类型的action即可触发请求,不会再出现循环。
内容的提问来源于stack exchange,提问作者expl
相关产品推荐
相关产品推荐

