前言
我们知道,redux提供了一套很好的状态管理机制,通过在createStore方法创建出store对象,通过store.getState获取状态对象,通过reducer定义出action改变对应的state变化的规则,通过replaceReducer动态改变reducer规则,结合dispatch一个action来修改状态对象state,甚至,redux还提供了applyMiddleware来给redux增加中间件,提供dispatch和getState2个方法给中间件使用;
不过,redux只是一个和其他库无关的状态管理库,为了能够方便的在react中使用,我们必须结合react-redux来使用。react-redux通过Provider使用给react项目的所有子组件注入store,通过connect给组件注入state和dispatch。
但是,有了react-redux还不够!我们还需要react-thunk!
为什么需要react-thunk?
ajax请求发出去的时候,经常涉及到这3个状态:loading,success,error3个状态,而且这3个状态是在同一个地方产生的,那么,如果仅有react-thunk,那么,我们需要在组件内部这样写代码:
this.props.dispatch(loadingAction);
ajax('/getData').then(res => {
this.props.dispatch(successAction);
}).catch(err => {
this.props.dispatch(errorAction);
})
如果上述代码在组件内多次被调用,就需要封装成函数,getData,如果要夸页面调,那就需要封装到专门的api请求里面去,代码如下:
//api.js
export function getData(dispatch) {
this.props.dispatch(loadingAction);
ajax('/getData').then(res => {
this.props.dispatch(successAction);
}).catch(err => {
this.props.dispatch(errorAction);
});
}
//index.js业务组件代码
import {getData} from './api.js';
class MyComponent extends Component {
handleClick() {
getData(this.props.dispatch);
}
}
并且,如果getData内部需要用到全局的state,那么,我们必须要从业务代码里面传入getState函数,那么代码就会变成下面这样:
//api.js
export function getData(dispatch, getState) {
const state = getState();
dispatch(loadingAction);
ajax('/getData').then(res => {
dispatch(successAction);
}).catch(err => {
dispatch(errorAction);
});
}
//index.js业务组件代码
import {getData} from './api.js';
class MyComponent extends Component {
handleClick() {
getData(this.props.dispatch, this.props.store.getState);
}
}
似乎这样也行,但是,总感觉不对,每次都要从业务组件里面显式的传入2个参数dispatch和getState,这样感觉很烦。
所以呢,通过以上分析,我们react-thunk就闪亮登场了!
react-thunk怎么用?
//store.js
import thunk from 'redux-thunk';
const initialState = {};
const reducer = function(state={}, action){ return state };
const store = createStore(reducer, initialState, applyMiddleware(thunk));
//action.js
export function getData(dispatch, getState) {
const state = getState();
dispatch(loadingAction);
ajax('/getData').then(res => {
dispatch(successAction);
}).catch(err => {
dispatch(errorAction);
});
}
//index.js业务组件代码
import { getData } from './actions.js';
class MyComponent extends Component {
handleClick() {
getData();
}
}
这样,使用了react-thunk之后,我们无需从getData中传入dispatch和getState,而是中间件会默认帮我们做这个事情,这样,我们就可以在一个函数内部dispatch多个action,以及随意的拿到全局的state
react-thunk怎么实现的?
看源码:
//一个创建thunk的中间件工厂函数
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
//创建出thunk中间件
const thunk = createThunkMiddleware();
//把工厂函数附属到thunk对象上,方便高级用户自定义传入更多的参数到action中去
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
其实,就是一个中间件的写法,当发现action是一个函数的时候,就会传入dispatch和getState这2个参数,而这2个参数是从中间件那里传过来的。
全文完
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。