为什么redux需要中间件?因为我们redux中有很多数据需要异步请求,所以需要中间件帮助我们在redux中完成异步请求。
1.redux-thunk中间件
1.1安装
yarn add redux-thunk
1.2 在store中使用
import { createStore, applyMiddleware } from 'redux'; // 导入应用中间件这个方法
import reducer from './reducer';
import thunkMiddleware from 'redux-thunk'; // 导入redux-thunk
const enhance = applyMiddleware(thunkMiddleware); // 生成一个enhancer
const store = createStore(reducer, enhance); // createStore中,可以传入第二个参数,enhancer
export default store;
1.3定义一个返回函数的action和另一个action
// 中间件在调用这个函数后,会传入dispatch和getState这两个参数,都是方法来的
export function getData() {
return (dispatch, getState) => {
axios
.get('https://api.apiopen.top/getJoke?page=1&count=2&type=video')
.then((res) => {
dispatch(get(res));
});
};
}
export function get(data) {
return {
type: types.GET,
data,
};
}
1.4 在页面上使用
import React, { PureComponent } from 'react';
import { getData } from './store/actionCreators';
import { connect } from 'react-redux';
class App extends PureComponent {
render() {
return (
<div>
{/*点击按钮发送异步请求*/}
<button onClick={(e) => this.props.getList()}>获取数据</button>
</div>
);
}
}
const mapStateToProps = (state) => ({
});
const mapDispatchToProps = (dispatch) => ({
getList: () => {
dispatch(getData()); // 在这里dispatch我们那个返回函数的action,记得调用getData
},
});
export default connect(mapStateToProps, mapDispatchToProps)(App);
1.5 在reducer中配置我们的get那个action
case types.GET:
console.log(action.data);
return { ...state, list: action.data };
redux-thunk的具体实现:redux-thunk在内部中,重写了dispatch方法,可以让dispatch方法可以接收一个函数作为参数,并将真正的dispatch和getState这个两个方法传给了那个函数。例如:
const store = {}
store.dispatch = () => {
console.log('dispatch')
}
const tem = store.dispatch
function newDispatch() {
console.log('加工')
tem()
console.log('加工')
}
store.dispatch = newDispatch
store.dispatch()
//输出: 加工 dispatch 加工
2.redux-saga中间件
2.1安装
yarn add redux-saga
2.2在store中配置并使用
import { createStore, applyMiddleware } from 'redux';
import reducer from './reducer';
// 2.redux-saga的配置:
import createSagaMiddleware from 'redux-saga'; // 导入创建saga中间件的方法
import saga from './saga'; // 导入我们自己编写的saga.js
const sagaMiddleware = createSagaMiddleware(); // 调用以下创建saga的方法,生成saga中间件
const enhancer = applyMiddleware(sagaMiddleware); // 应用中间件
const store = createStore(reducer, enhancer); // 在创建store的时候传enhancer进去
sagaMiddleware.run(saga); // run以下saga
export default store;
2.3创建两个action,一个是触发saga的action,另一个是修改store的action
// 触发saga的媒介,你有多少个要修改store的action,就有多少个这样触发saga的媒介action
export function saga() {
return {
type: 'SAGA',
};
}
export function changeDataBySaga(data) {
return {
type: 'CHANGE_DATA',
data,
};
}
2.4创建并编写saga.js文件
// 在redux-saga/effects中,可以导出我们需要的takeLatest,put,all,takeEvery方法
import { takeLatest, put, all,takeEvery } from 'redux-saga/effects';
// 导入我们需要的修改Store的action
import { getDataBySaga } from './actionCreators';
import axios from 'axios';
// 捕获到action的处理函数
function* getdata() {
// 利用yield的特性,可以获取到异步的结果
const res = yield axios.get(
'https://api.apiopen.top/getJoke?page=1&count=2&type=video'
);
// 使用put方法dispatch我们的action
yield put(changeDataBySaga(res));
// 如果有多个put,我们可以使用all这个函数:
// yield all([
//put(changeDataBySaga(res)),
//put(changeDataBySaga1(res1))
])
}
// 创建generator函数,并将这个函数导出
function* mySaga() {
yield takeLatest(‘SAGA’, getdata);
// yield takeEvery('SAGA', getdata);
// yield all([
//takeEvery('SAGA',getdata),
//takeLatest('SAGA1',getdata1),
//takeLatest('SAGA2',getdata2)
])
// 我们这里是takeLatest是用来捕获action的type为SAGA的,如果捕获到就交给getdata这个generator进行处理
// takeLatest和takeEvery的区别:当我们短时间内,触发多次action,takeLatest只捕获最后一次,而takeEvery每次都捕获。
// all方法的使用:可以让你少写yield这个单词,你将你所需要捕获的takeEvery或者takeLatest放进数组中,并传给all方法,他就会自动帮你调用了
}
export default mySaga;
解释说明:function*和yield是es6中的generator语法,生成器函数,不懂的可以去百度了解一下。
2.5在页面中使用
import React, { PureComponent } from 'react';
import { saga } from './store/actionCreators';
import { connect } from 'react-redux';
class App extends PureComponent {
render() {
return (
<div>
<button onClick={(e) => this.props.getListBySaga()}>
获取数据BySaga
</button>
</div>
);
}
}
const mapStateToProps = (state) => ({
});
const mapDispatchToProps = (dispatch) => ({
getListBySaga: () => {
dispatch(saga()); // dispatch我们那个action媒介,让saga可以捕获
},
});
export default connect(mapStateToProps, mapDispatchToProps)(App);
redux-saga的实现思路:有点像设计模式中的监听者和观察者的模式,saga监听着是否有需要进行异步操作的action进行dispatch,如果有,就进行对应的异步操作,再通过dispatch另一个action来修改我们store中的数据。