用户发出 Action,Reducer 函数算出新的 State,View 重新渲染。但是,一个关键问题没有解决:异步操作怎么办?Action 发出以后,Reducer 立即算出 State,这叫做同步;Action 发出以后,过一段时间再执行 Reducer,这就是异步。
怎么才能 Reducer 在异步操作结束后自动执行呢?这就要用到新的工具:中间件(middleware)。
Github:https://github.com/gaearon/redux-thunk
一.redux-thunk
redux-thunk 是一个比较流行的 redux 异步 action 中间件,比如 action 中有 ****setTimeout**** 或者通过 ****fetch****通用远程 API 这些场景,那么久应该使用 redux-thunk 了。redux-thunk 帮助你统一了异步和同步 action 的调用方式,把异步过程放在 action 级别解决,对 component 没有影响。
1.中间件的概念
如果要添加功能,你会在哪个环节添加?
(1)Reducer:纯函数,只承担计算 State 的功能,不合适承担其他功能,也承担不了,因为理论上,纯函数不能进行读写操作。 (2)View:与 State 一一对应,可以看作 State 的视觉层,也不合适承担其他功能。 (3)Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作。
想来想去,只有发送 Action 的这个步骤,即store.dispatch()方法,可以添加功能。举例来说,要添加日志功能,把 Action 和 State 打印出来,可以对store.dispatch进行如下改造。
let next = store.dispatch; store.dispatch = function dispatchAndLog(action) { console.log('dispatching', action); next(action); console.log('next state', store.getState()); }
上面代码中,对store.dispatch进行了重定义,在发送 Action 前后添加了打印功能。这就是中间件的雏形。
中间件就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能。
二.例子
从上一篇:Redux基本语法 机关枪的例子
这边补充异步的操作:
index.redux.js
//延迟添加 拖俩天再给 export function addGunAsync(){ //thunk插件的作用,这里可以返回函数 return dispatch =>{ //异步结束后,手动执行dispatch setTimeout(() => { dispatch(addGUN()) }, 2000) } }
index.js
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import registerServiceWorker from './registerServiceWorker'; import { createStore ,applyMiddleware} from 'redux'; import thunk from 'redux-thunk'; import {counter,addGUN,removeGUN,addGunAsync} from './index.redux'; //1.新建store const store = createStore(counter,applyMiddleware(thunk)); function render() { //reactDOM 渲染页面 //2.这个store 以在组件属性props传给Component 组件 ReactDOM.render(<App store={store} addGunAsync={addGunAsync} addGUN={addGUN} removeGUN={removeGUN} />, document.getElementById('root')); registerServiceWorker(); } render(); //3.以subscribe订阅render的函数 这样我们可以知道state的变化 store.subscribe(render);
app.js
import React from 'react'; class App extends React.Component { render() { //4.通过组件的属性props 获取store以及数据操作addGUN //5.在通过dispatch(addGUN()) 发送action const store=this.props.store; const num =store.getState(); const addGUN=this.props.addGUN; const removeGUN=this.props.removeGUN; const addGunAsync=this.props.addGunAsync; return ( <div> <h1>现在有机枪{num}把</h1> <button onClick={()=>store.dispatch(addGUN())}>申请武器</button> <button onClick={()=>store.dispatch(removeGUN())}>上交武器</button> <button onClick={()=>store.dispatch(addGunAsync())}>拖2天上交武器</button> </div> ); } } export default App;
点击拖2天上交武器按钮 过2秒后 会自动加1把机关枪 ,这就是异步操作。