一、为什么使用 redux-thunk
- redux-thunk 是 redux 的异步中间件
- redux-thunk 是对 store.dispatch 方法的升级,如果不使用 redux-thunk,那么 store.dispatch 只能传入对象,不可传入函数,使用 redux-thunk 后不仅可以传入对象,也可传入一个 action 函数,并自动执行这个函数
- 可以在 action 函数中做异步数据请求等操作,也可将 action 函数逻辑处理单独抽离,便于单元测试,
二、使用 redux-thunk
1. 安装 redux-thunk
npm install redux-thunk -S
2. 在 src\store\index.js 中配置 redux-thunk
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';
// 使用 redux-devtool
const composeEnhancers = typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
// 使用 redux-thunk 中间件
const enhancer = composeEnhancers(applyMiddleware(thunk));
const store = createStore(reducer, enhancer);
export default store;
3. 在组件中,把 action 定义成一个函数
示例:componentDidMount 生命周期中模拟异步获取数据
import React, { Component } from 'react';
import store from '../../store';
class Test extends Component {
constructor(props) {
super(props);
this.state = {
username: store.getState().username,
};
}
render() {
return (
<>
<div>
<label htmlFor="uname">用户名:</label>
<input id="uname" type="text" defaultValue={this.state.username} />
</div>
</>
);
}
componentDidMount() {
store.subscribe(this.storeUsernameChange.bind(this));
// const action = {
// type: 'change_username',
// value: e.target.value,
// };
const action = (dispatch) => {
setTimeout(() => {
const data = {
username: 'alias',
};
const action = {
type: 'change_username',
value: data.username,
};
dispatch(action);
}, 2000);
};
store.dispatch(action);
}
storeUsernameChange() {
this.setState((prevState) => ({
username: store.getState().username,
}));
}
}
export default Test;
4. 将 action 处理过程抽离出来
- 创建 src\store\actions.js
export const initUsernameAction = () => {
return (dispatch) => {
setTimeout(() => {
const data = {
username: 'alias',
};
const action = {
type: 'change_username',
value: data.username,
};
dispatch(action);
}, 2000);
};
};
- 在组件中引入并使用
import React, { Component } from 'react';
import store from '../../store';
import { initUsernameAction } from '../../store/actions';
class Test extends Component {
constructor(props) {
super(props);
this.state = {
username: store.getState().username,
};
}
render() {
return (
<>
<div>
<label htmlFor="uname">用户名:</label>
<input id="uname" type="text" defaultValue={this.state.username} />
</div>
</>
);
}
componentDidMount() {
store.subscribe(this.storeUsernameChange.bind(this));
store.dispatch(initUsernameAction());
}
storeUsernameChange() {
this.setState((prevState) => ({
username: store.getState().username,
}));
}
}
export default Test;
网友评论