6-4 使用Redux-thunk 中间件实现ajax数据请求
第一步,安装: yarn add redux-thunk
第二步,在store/index.js中引入applyMiddleware:
import { createStore, applyMiddleware, compose } from 'redux';
applyMiddleware使我们可以使用中间件
第三步,引入thunk,在store/index.js中引入:
import thunk from 'redux-thunk';
第四步,将thunk注册到applyMiddleware中,使thunk成为store的中间件(因为applyMiddleware属于redux)
(注意:redux在创建store的时候才能用中间件,thunk是redux的中间件)
(除了thunk,调错工具某种意义上来讲也是中间件)
第五步,因为中间件有两个,通过redux的compose可以实现注册两个或以上中间件,这也是redux注册中间件的高级写法。
代码:
import { createStore, applyMiddleware, compose } from 'redux';
import reducer from './reducer';
import thunk from 'redux-thunk';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(
applyMiddleware(thunk),
);
const store = createStore(reducer, enhancer);
export default store;
这里,enhancer就是两个中间件。原先应是 applyMiddleware([thunk,window.__REDUX_DEVTOOLS_EXTENSION_.....])
react–>jsx编译。只有import React from ‘react’ 才能用jsx语法。(不管是无状态组件函数也是一样的)
关于thunk:
1、不使用中间件,store接收的action只能是对象;有了中间件(redux-thunk),action可以是一个函数,通过store.dispatch这个方法将action函数传给store。
2、store接收到action之后发现action是函数而不是对象,则会执行调用这个action函数。
3、action函数内部先进行异步请求获取数据,之后去改变store中的数据(state)。
4、首先内部创建一个action对象,外部action这个函数默认接收store的dispatch方法,因此直接调用dispatch方法将内部action对象传给store,store便可以更新数据。
以上,已经完成了关于redux-thunk的注册了。接下来就是看怎么用。
redux-thunk的作用就是将异步操作移到action那里去。
原本,action是个对象,因为thunk,action可以作为一个函数。
代码,看getTodoList怎么写的:
store/actionCreator.js中(专门写action的地方)
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM, INIT_LIST_ACTION } from './actionTypes';
import axios from 'axios';
export const getInputChangeAction = (value) => ({
type: CHANGE_INPUT_VALUE,
value
});
export const getAddItemAction = () => ({
type: ADD_TODO_ITEM
});
export const getDeleteItemAction = (index) => ({
type: DELETE_TODO_ITEM,
index
});
export const initListAction = (data) => ({
type: INIT_LIST_ACTION,
data
});
export const getTodoList = () => {
return (dispatch) => {
axios.get('/list.json').then((res) => {
const data = res.data;
const action = initListAction(data);
dispatch(action);
})
}
}
在组件中是:
import { getTodoList, getInputChangeAction, getAddItemAction, getDeleteItemAction } from './store/actionCreators'
componentDidMount() {
const action = getTodoList();
store.dispatch(action);
}
这里:getTodoList是函数。是特殊的action。
store.dispatch(action),当action是函数时,执行这条语句会自动执行。
该action函数可以接收到store的dispatch。
所以就是
(dispatch) = > {
axios.get('./list.json').then((res)=>{
const data = res.data
const action = initListAction(data)
dispatch(action)
}
}
看了一下别人解释的thunk,所谓thunk,中间件,它就是在action和store之间,也就是dispatch,thunk是对dispatch
的封装。当传入dispatch是函数时,它允许函数先执行,等到函数里面执行了dispatch(对象),即dispatch(action),action
时对象时,再调用store去管理action
dispatch会根据参数的不同,执行不同的事情。
redux还有其它中间件,比如redux-logger,可以记录action每次派发的日志。
解决redux异步的中间件除了redux-thunk,还有redux-saga
redux的所有中间件指的都是action和store的中间。
使用redux-saga中间件:redux-saga跟redux-thunk一样,都是实现将异步操作放在action。
第一步:yarn add saga
第二步:store/index.js:
import { createStore, applyMiddleware, compose } from 'redux';
import reducer from './reducer';
import createSagaMiddleware from 'redux-saga';
import todoSagas from './sagas';
const sagaMiddleware = createSagaMiddleware();
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware));
const store = createStore(reducer, enhancer);
sagaMiddleware.run(todoSagas);
export default store;
第三步,由于saga将异步的逻辑放在单独的文件里,因此创建store/sagas.js,就是上面那个todoSagas,
这个中间件除了在createStore创建后,还需要使用sagaMiddleware.run(todoSagas);语句。
TodoSagas是一个generator函数。
saga可以捕获action。(通过takeEvery)
function* mySaga() {
yield takeEvery(GET_INIT_LIST, getInitList);
}
mySaga通过捕捉action.type===GET_INIT_LIST的action,在它进入store之前先执行getinitList函数。
getinitList函数里面可以写很多代码,比如可以写异步相关代码。
整体mySaga代码如下:(store/sagas.js)
import { takeEvery, put } from 'redux-saga/effects';
import { GET_INIT_LIST } from './actionTypes';
import { initListAction } from './actionCreators';
import axios from 'axios';
function* getInitList() {
try {
const res = yield axios.get('/list.json');
const action = initListAction(res.data);
yield put(action);
}catch(e) {
console.log('list.json网络请求失败');
}
}
// generator 函数
function* mySaga() {
yield takeEvery(GET_INIT_LIST, getInitList);
}
export default mySaga;
注意:1.因为sagas.js里没有store,所以无法store.dispatch(action),只能 put(action)
2.在generator函数里,异步函数不用promise,用yield即可,代码:const res = yield axios.get('/list.json');
yield证明会等待,会等待获得res再执行下面的语句。
3.yield put(action)
;(generator函数的专属写法,跟store.dispatch(action)
是一个意思,这里action是对象)
4.因为yield axios.get(‘/list.json’);代替了promise,但这样没有then或catch,如果出错了就会出现问题,所以需要用到try…catch
redux-thunk适合简单项目,比起redux-saga,没有太多api,只是action既可以是对象,也可以是函数。
thunk允许函数在执行到dispatch(action)后,再将action派发给store.
今天在学打包,呃,其实好像很简单,主要是部署交给测试做了,但我觉得迟早有一天需要我去做,找个时间学一下吧!
两个打包,打包后压缩dist目录,把dist压缩包发给测试。一共有两个,
npm run build:prod,这是仿真环境。
npm run build:stage,这是测试环境