之前我们使用redux-thunk 把异步代码放到了action 里面,这个解决了自动化测试的一些问题以及代码的拆分管理。
redux-saga 也是做异步代码拆分的中间件,可以把它将 redux-thunk 互换。
我们要使用redux-saga,先把之前redux-thunk 相关代码删掉。
然后,我们在github 上找到 redux-saga : https://github.com/redux-saga/redux-saga
按照github 中的文档,我们先下载按照 redux-saga ,使用命令
yarn add redux-saga
安装好啦后,我们就开始使用了。首先在store 文件中,引入并使用,如下。
import { createStore, applyMiddleware } from 'redux';
// import thunk from 'redux-thunk';
import reducer from './reducer';
import createSagaMiddleware from 'redux-saga';
import mySaga from './sagas';
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
reducer,
// applyMiddleware(thunk)
applyMiddleware(sagaMiddleware)
);
sagaMiddleware.run(mySaga);
export default store;
然后,我们在store 文件夹下新建一个sagas.js ,我们把异步代码都放这儿。
我们先把github 上 sagas.js 中后面几行代码拷到 sagas.js (必须有一个函数是generator函数)中,如下。
function* mySaga() {
//yield takeLatest("USER_FETCH_REQUESTED", fetchUser);
}
export default mySaga;
下面,我们要将组件中axios 异步代码,移到sagas.js 中,
首先,我们创建一个action 模版把
export const getInitListAction = () => ({
type: GET_INIT_LIST
})
然后在组件中使用,并传给redux
componentDidMount() {
const action = getInitListAction();
store.dispatch(action);
console.log(action);
}
然后呢,在传给store之前,我们在saga中处理它,进入sagas.js 文件,进行修改:(下面的意思是,saga 只要捕获到 GET_INIT_LIST 就会执行 fetchUser方法)
import { takeEvery } from 'redux-saga/effects';
import {GET_INIT_LIST} from './actionTypes';
function* mySaga() {
yield takeEvery( GET_INIT_LIST, fetchUser);
}
export default mySaga;
下面我们来写一个fetchUser方法,如下。 fetchUser 方法可以是普通方法也可以是gennerator 方法,建议写generator 方法。
import { takeEvery } from 'redux-saga/effects';
import store from './index.js';
import {GET_INIT_LIST} from './actionTypes';
import axios from 'axios';
import {
initListAction
} from './actionCreators';
function* initList () {
axios.get('api/list.json', {dataType: 'json'}).then((res) => {
const action = initListAction(res.data.names);
store.dispatch(action);
})
}
function* mySaga() {
yield takeEvery( GET_INIT_LIST, initList);
}
export default mySaga;
上面代码,好像没问题,但是redux-saga 给我们提供了put 方法,就不用store 的dispatch 了,如下。【在generator 函数 里,做异步请求的话,就不要用Promise了,完全可以用yield】
import { takeEvery, put } from 'redux-saga/effects';
import {GET_INIT_LIST} from './actionTypes';
import axios from 'axios';
import {
initListAction
} from './actionCreators';
function* initList () {
const res = yield axios.get('api/list.json');
const action = initListAction(res.data.names);
yield put(action);
}
function* mySaga() {
yield takeEvery( GET_INIT_LIST, initList);
}
export default mySaga;
我们可以给 yield 加一个try 如下。
function* initList () {
try {
const res = yield axios.get('api/list.json');
const action = initListAction(res.data.names);
yield put(action);
} catch(e) {
console.log("list.json 请求失败")
}
}
然后组件中只需要如下代码。即可使用异步代码。
componentDidMount() {
const action = getInitListAction();
store.dispatch(action);
}
Done