1.什么是中间件?
如果有学习过Node
的Express
框架的童孩应该对中间件不陌生。在Express
框架中,中间件就是一个函数
,这个函数是用来处理请求的过程的,那么在Redux
中的中间件也基本类似。Redux的中间件是专门用来处理dispatch分发的action
。
例如,Redux中间件的使用:
ui-->action-->store-->中间件-->中间件(...)-->reducer-->store--> ui
2.定义函数式的Action
在以前的案例中,我们定义的所有的action
都是一个对象类型的action
(必须有一个type属性)。 那么下面来介绍一下函数式的action
。
例如:
/*1.对象类型的action*/
var finish=(str)=>{
return{
type:'finish',
str:str,
}
}
/*2.函数类型的action*/
var getData=()=>{
return(dispatch, getState)=>{
/*分发一个action*/
dispatch(loading('加载中...'))
setTimeout(()=>{
/*过1s后在分发一个action*/
dispatch(finish('加载完成...'))
},1000)
}
}
上面的getData()
函数就是一个函数式的action
,这个函数直接返回了箭头函数,这个箭头函数会接收到两个参数,一个是:dispatch, 一个是:getState
。这两个参数是谁传递传过来的?是我们下面将要定义的中间件函数createThunkMiddleware()
传递过来的。
那这个函数式的action 如何分发?
这个时候就要用到Redux的中间件技术
。
3.中间件技术
1.定义一个中间件
下面定义的中间件的方式可以看做是中间件的模板
。
中间件的模板定义 , 例如:
({dispatch,getState})=>(next)=>(action)=>{ }
/*
自定义一个中间件( 这个中间件什么事情都没有做 )
*/
function createThunkMiddleware() {
return function ({dispatch,getState}) {
return function (next) {
return function (action) {
//....
return next(action);
}
}
}
}
// or 简写成函数式的编程
var createThunkMiddleware=()=>{
return ({dispatch,getState})=>(next)=>(action)=>{
//...
return next(action);
}
}
2.中间件处理函数式的Action
/*自定义一个中间件:专门处理函数类型的action*/
function createThunkMiddleware() {
return function ({dispatch,getState}) {
return function (next) {
return function (action) {
/**专门处理函数类型的action*/
if(typeof action === 'function'){
/*这里将dispatch,getState两个参数传递给函数式的action*/
return action(dispatch,getState);
}
return next(action);
}
}
}
}
3.在创建Store时应用中间件
/**ES6的方式导入(注意有些IDE不支持import语法, 也使用ES5的require导入)*/
import {createStore,applyMiddleware} from 'redux';
var initValue={
str:'',
}
/**
* 参数一: reducer函数
* 参数二: 初始化状态树
* 参数三: 应用中间件
* @type {Store<S>}
*/
var store =createStore( reducer,initValue,applyMiddleware(createThunkMiddleware()) );
4.完整代码
/*==================action=====================*/
/*1.对象类型的action*/
var loading=(str)=>{
return{
type:'loading',
str:str,
}
}
/*1.对象类型的action*/
var finish=(str)=>{
return{
type:'finish',
str:str,
}
}
/*2.函数类型的action*/
var getData=()=>{
return(dispatch, getState)=>{
dispatch(loading('加载中...'))
setTimeout(()=>{
dispatch(finish('加载完成...'))
},1000)
}
}
/*==================reducer=====================*/
var reducer=(state,action)=>{
var {str,type}=action;
switch (type){
case 'loading':
var s=Object.assign({},state,{str:str});
console.log(s);
return s;
case 'finish':
var s=Object.assign({},state,{str:str});
console.log(s);
default:
return state;
}
}
/*==================中间件====================*/
/*自定义一个中间件:专门处理函数类型的action*/
function createThunkMiddleware() {
return function ({dispatch,getState}) {
return function (next) {
return function (action) {
if(typeof action === 'function'){
return action(dispatch,getState);
}
return next(action);
}
}
}
}
/*==================store=====================*/
import {createStore,applyMiddleware} from 'redux';
var initValue={
str:'',
}
/**
* 参数一: reducer函数
* 参数二: 初始化状态树
* 参数三:添加中间件
* @type {Store<S>}
*/
var store =createStore( reducer,initValue,applyMiddleware(createThunkMiddleware()) );
/*==================简单使用====================*/
console.log('初始化的状态树:',store.getState());
/*1.分发一个 getData() 事件*/
store.dispatch( getData() );
执行后控制台输出:
初始化的状态树: { str: '' }
{ str: '加载中...' }
{ str: '加载完成...' } // 一秒后才打印
5.查看中间件的调用过程
刚才编写的这个createThunkMiddleware()
中间件在 哪里被调用?如何调用?它的参数是如何接收到的?
下面就带着大家查看Redux
的源码的实现。
function createThunkMiddleware() {
/**参数{dispatch,getState}是如何接收到的?*/
return function ({dispatch,getState}) {
/** next 是一个函数,是哪个函数? */
return function (next) {
/** 中间件如何接收到用户发出的action */
return function (action) {
if(typeof action === 'function'){
return action(dispatch,getState);
}
return next(action);
}
}
}
}
1.查看applyMiddleware()函数源码
刚才编写的这个createThunkMiddleware()
中间件在是在applyMiddleware()
这个函数中被使用。所以先看这个函数的实现:
/**
参数...middlewares :代表可接收一个数组的中间件(我们案例只有一个)
返回:返回结果是一个函数 (createStore)=> ( , , )=>{ }。
*/
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.dispatch
let chain = []
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
applyMiddleware( )
函数返回结果
是一个函数:(createStore)=> ( )=>{ }
;那么这个函数被谁调用了?参数在哪里传递进来的? 查看: createStore(reducer,initState,middleware)
源码:
export default function createStore(reducer, preloadedState, enhancer) {
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
/**
applyMiddleware( )函数返回结果是一个函数: 原来在这里被调用了
例如: enhancer(createStore); 但是这个函数又返回一个函数
那就再调用:enhancer(createStore)(reducer, preloadedState)
*/
return enhancer(createStore)(reducer, preloadedState)
}
}
经过上面enhancer(createStore)(reducer, preloadedState)
的函数调用,那么applyMiddleware( )函数
返回的函数就被调用了,并且参数也传递过去了。
在回看 applyMiddleware()函数:
/**参数..middlewares: 接收我们编写的中间件*/
export default function applyMiddleware(...middlewares) {
/** (createStore )=>(reducer, preloadedState, enhancer)*/
/**上面的参数都是在:enhancer(createStore)(reducer, preloadedState)传递过来的*/
return (createStore) => (reducer, preloadedState, enhancer) => {
/**创建store*/
const store = createStore(reducer, preloadedState, enhancer)
/**备份dispathc函数(简写:next)*/
let dispatch = store.dispatch
let chain = []
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
/**我们的中间件在middleware(middlewareAPI)被传递了参数:{getState,dispatch}*/
chain = middlewares.map(middleware => middleware(middlewareAPI))
/**我们的中间件在compose(...chain)里面被调用了*/
/**compose(...chain)返回的是函数,那就接着调用,并传递参数:store.dispatch*/
dispatch = compose(...chain)(store.dispatch)
/**最后再重写了store中的dispatch函数*/
return {
...store,
dispatch
}
}
}
接下来看我们编写的中间件createThunkMiddleware()
:
function createThunkMiddleware() {
/**参数{dispatch,getState}是在middleware(middlewareAPI)传递进来的*/
return function ({dispatch,getState}) {
/**参数next 是在compose(...chain)(store.dispatch) 传递进来的*/
/**next 其实就是没有被重写的store.dispatch函数*/
return function (next) {
/**最后的这个函数赋值给store中的dispatch函数,参数就是用户分发action的参数*/
return function (action) {
if(typeof action === 'function'){
return action(dispatch,getState);
}
return next(action);
}
}
}
}