react-thunk

简介

在 reducers 中的所有操作都是同步的并且是纯粹的,即 reducer 都是纯函数,纯函数是指一个函数的返回结果只依赖于它的参数,并且在执行过程中不会对外部产生副作用,即给它传什么,就吐出什么。但是在实际的应用开发中,可能希望做一些异步的(如Ajax请求,异步获取数据,访问浏览器缓存)且不纯粹的操作(如改变外部的状态),这些在函数式编程范式中被称为“副作用”。

Redux 的作者将这些副作用的处理通过提供中间件的方式让开发者自行选择进行实现。

redux-thunk 和 redux-saga 是 redux 应用中最常用的两种异步流处理方式。

redux-thunk中间件可以让action创建函数先不返回一个action对象,而是返回一个函数,函数传递两个参数(dispatch,getState),在函数体内进行有负作用的业务逻辑封装,处理完所需的异步操作后,再发送其它 action 去修改 state。

使用方式

  • 安装:npm install redux-thunk –save-dev
  • 导入thunk: import thunk from ‘redux-thunk’
  • 导入中间件: import {createStore,applyMiddleware} from ‘redux’
  • 创建store:let store = createStore(reducer函数,applyMiddleware(thunk))
  • 激活redux-thunk中间件,只需要在createStore中加入applyMiddleware(thunk)就可以

代码

以一个计数器为例

当点击自增按钮时,2秒后再对 store 的值进行自增。

action

src/container/action.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 自增请求
export function handleIncreaseAction(num) {
return {
type: "increase",
num: num
};
}

// 自减请求
export function handleInReduceAction(num) {
return {
type: "inReduce",
num: num
};
}

// 异步自增请求
export function handleIncreaseActionAsync(num) {
// getState() 拿到当前 store 的值
return async (dispatch, getState) => {
console.log('getState',getState());
await asyncFn();
//分发一个任务
dispatch(handleInReduceAction());
};
}

async function asyncFn() {
return new Promise(resolve => {
setTimeout(() => {
console.log("2s end");
resolve();
}, 2000);
});
}

激活redux-thunk中间件

src/configureStore.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React from "react";
import ReactDOM from "react-dom";
import "./style/index.scss";
import registerServiceWorker from "./registerServiceWorker";
import CRouter from "./router";
import thunk from 'redux-thunk'
import {
createStore,
applyMiddleware,
} from "redux";
import createReducer from './reducers';

// redux
import { Provider } from "react-redux";

const store = createStore(createReducer(),applyMiddleware(thunk));

ReactDOM.render(
<Provider store={store}>
<CRouter/>
</Provider>,
document.getElementById("root")
);
registerServiceWorker();

组件

Counter.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import React, { Component } from "react";
import { connect } from "react-redux";
import { handleInReduceAction, handleIncreaseActionAsync } from './actions'
class Counter extends Component {
render() {
const { value, onIncreaseClick, onReduceClick } = this.props;
return (
<div>
<span>{value}</span>
<button onClick={onIncreaseClick}>增加</button>
<button onClick={onReduceClick}>减少</button>
</div>
);
}
}

function mapStateToProps(state) {
return {
value: state.counterReducer.count
};
}

function mapDispatchToProps(dispatch) {
return {
onIncreaseClick: () => {
dispatch(handleIncreaseActionAsync());
},
onReduceClick: () => {
dispatch(handleInReduceAction());
}
};
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(Counter);
本文结束,感谢您的阅读