资讯专栏INFORMATION COLUMN

Redux入门0x105: redux 中间件

brianway / 710人阅读

摘要:概述前一章讲了的,这一章讲中很神奇的中间件。我们也可以使用中间件来扩展的功能。当然一样的,这样的中间件也已经存在了,日志的中间件也已经存在了查看效果资源源码

0x000 概述

前一章讲了reduxAction Creator,这一章讲redux中很神奇的中间件。

0x001 手写中间件

在项目中,我们经常会有记录一些事件或者在某些事件发生的时候做某些事的需求,比如api接口鉴权操作、日志记录操作等,一般我们都可以用中间件来完成,中间件具有可拔插、可扩展的特点。我们也可以使用中间件来扩展redux的功能。

记录每一次的actionstate变化
我们在之前是这么使用redux的:

import {createStore} from "redux"

function counter(state = 0, action) {
    switch (action.type) {
        case "INCREMENT":
            return state + 1
        default:
            return state
    }
}

let store = createStore(counter)

store.subscribe(() => {
    // console.log(store.getState())
})

const ACTION_INCREMENT = "INCREMENT"

const increment = () => {
    return {
        type: ACTION_INCREMENT
    }
}
const action = increment()
store.dispatch(action)
store.dispatch(action)
store.dispatch(action)

通过store.dispatch完成对数据的修改,现在我们希望记录每一次对数据的修改,我们可以这么做

console.log("action", action.type)
store.dispatch(action)
console.log("next state", store.getState())

console.log("action", action.type)
store.dispatch(action)
console.log("next state", store.getState())

console.log("action", action.type)
store.dispatch(action)
console.log("next state", store.getState())

效果很明显,猪才会这么做

封装1:封装成函数,可以,经常我们也是这么做的,但是不好

const dispatch = (store, action) => {
    console.log("action", action.type)
    store.dispatch(action)
    console.log("next state", store.getState())
}

dispatch(store, action)

封装2:hackstore.dispatch,没毛病,但是不够优雅并且如果希望有多个中间件不太好办,并且希望中间键可以串联起来

const storeDispatch=store.dispatch
store.dispatch= (action) => {
    console.log("action", action.type)
    storeDispatch(action)
    console.log("next state", store.getState())
}
store.dispatch(action)

封装3:多个中间件串联

这里写了两个中间键,一个是前中间件,一个是后中间件,在执行 before(store)的时候,其实我们已经将store.dispatch替换成了beforedispatch,所以我们在afterdispatch第二次替换的时候,const storeDispatch = store.dispatch中的 store.dispatch其实是before.dispatch,所以,当我们执行store.dispatch(increment())的时候,调用链其实是:store#dispatch=after#dispatch -> before#dispatch -> before#console.log -> store#dispatch -> after#console.log
const before = (store) => {
    const storeDispatch = store.dispatch
    const dispatch=(action) => {
        console.log("before", action.type,store.getState())
        storeDispatch(action)
    }
    store.dispatch = dispatch
}

const after = (store) => {
    const storeDispatch = store.dispatch
    const dispatch = (action) => {
        storeDispatch(action)
        console.log("after",action.type,store.getState())
    }
    store.dispatch=dispatch
}
before(store)
after(store)
store.dispatch(increment())

查看输出:

封装4:隐藏hack,减少样板代码

const before = (store) => {
    const storeDispatch = store.dispatch
    return (action) => {
        console.log("before", action.type, store.getState())
        storeDispatch(action)
    }
}

const after = (store) => {
    const storeDispatch = store.dispatch
    return (action) => {
        storeDispatch(action)
        console.log("after", action.type, store.getState())
    }
}

const applyMiddleware = (store, ...middlewares) => {
    middlewares.reverse()
    middlewares.forEach(middleware => {
        store.dispatch = middleware(store)
    })
}

applyMiddleware(store, before, after)

store.dispatch(increment())

封装5:不使用 hack

const before = (store) => {
    return (storeDispatch) => {
        return (action) => {
            console.log("before", action.type, store.getState())
            storeDispatch(action)
        }
    }
}
const after = (store) => {
    return (storeDispatch) => {
        return (action) => {
            storeDispatch(action)
            console.log("after", action.type, store.getState())
        }
    }
}

const applyMiddleware = (store, ...middlewares) => {
    middlewares.reverse()
    let storeDispatch = store.dispatch
    middlewares.forEach(middleware => {
        storeDispatch = middleware(store)(storeDispatch)
    })
    // store.dispatch = storeDispatch
    return {...store, ...{dispatch: storeDispatch}}
}

store = applyMiddleware(store, before, after)

store.dispatch(increment())

封装6:优化中间件写法

const before = store => storeDispatch => action => {
    console.log("before", action.type, store.getState())
    return storeDispatch(action)
}
const after = store => storeDispatch => action => {
    let result = storeDispatch(action)
    console.log("after", action.type, store.getState())
    return result
}

最终的完整代码

import {createStore} from "redux"

// reducer
function counter(state = 0, action) {
    switch (action.type) {
        case "INCREMENT":
            return state + 1
        default:
            return state
    }
}
// 创建 store
let store = createStore(counter)

// action
const ACTION_INCREMENT = "INCREMENT"

// action creator
const increment = () => {
    return {
        type: ACTION_INCREMENT
    }
}

// 前中间件
const before = store => storeDispatch => action => {
    console.log("before", action.type, store.getState())
    return storeDispatch(action)
}

// 后中间件
const after = store => storeDispatch => action => {
    let result = storeDispatch(action)
    console.log("after", action.type, store.getState())
    return result
}

// 应用中间件
const applyMiddleware = (store, ...middlewares) => {
    middlewares.reverse()
    let storeDispatch = store.dispatch
    middlewares.forEach(middleware => {
        storeDispatch = middleware(store)(storeDispatch)
    })
    // store.dispatch = storeDispatch
    return {...store, ...{dispatch: storeDispatch}}
}

// 返回了新的 store
store = applyMiddleware(store, before, after)

// 发出 action 
store.dispatch(increment())

0x002 redux applyMiddleware
前面写了一个applyMiddleware方法,虽然可以用,但是官方其实也提供了这个方法,并且比我们写的更好一点
const before = store => storeDispatch => action => {
    console.log("before", action.type, store.getState())
    return storeDispatch(action)
}
const after = store => storeDispatch => action => {
    let result = storeDispatch(action)
    console.log("after", action.type, store.getState())
    return result
}
let store = createStore(counter, applyMiddleware(before, after))
store.dispatch(increment())
可以看出来,相较于我们自己写的`applyMiddleware`,官方提供的可以直接传递给`createStore`,而无需在次对`store`进行操作。
0x003 异步action
const before = store => storeDispatch => action => {
    console.log("before", action.type, store.getState())
    return storeDispatch(action)
}
const after = store => storeDispatch => action => {
    let result = storeDispatch(action)
    console.log("after", action.type, store.getState())
    return result
}
const asyncAction=()=>{
    return (dispatch)=>{
        setInterval(()=>{
            dispatch(increment())
        },1000)
    }
}
const asyncMiddleware = store => storeDispatch => action => {
    if (typeof action === "function") {
        return action(storeDispatch)
    } else {
        return storeDispatch(action)
    }
}
let store = createStore(counter, applyMiddleware(asyncMiddleware,before,after))
store.dispatch(asyncAction())

这里写了一个asyncMiddleware,他判断传入的action是否是一个函数,如果是一个函数,那就直接执行这个函数,同时将dispatch作为参数,则在asyncAction我们就能直接访问到dispatch了,就可以在asyncAction适当的时候再次dispatch了。
当然一样的,这样的中间件也已经存在了:redux-thunk,日志的中间件也已经存在了:redux-logger

import thunkMiddleware from "redux-thunk"
import { createLogger } from "redux-logger"

const store = createStore(
    counter,
    applyMiddleware(
        thunkMiddleware,
        createLogger()
    )
)
store.dispatch(increment())

查看效果

0x004 资源

源码

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97936.html

相关文章

  • Router入门0x201: 从 URL 到 SPA

    摘要:的全称是统一资源定位符英文,可以这么说,是一种标准,而网址则是符合标准的一种实现而已。渲染器,将组件渲染到页面上。 0x000 概述 从这一章开始就进入路由章节了,并不直接从如何使用react-route来讲,而是从路由的概念和实现来讲,达到知道路由的本质,而不是只知道如何使用react-route库的目的,毕竟react-route只是一个库,是路由的一个实现而已,而不是路由本身。 ...

    honmaple 评论0 收藏0
  • Redux 入门

    摘要:系列文章入门本文进阶番外篇状态管理,第一次听到这个词要追溯到去年年底。只读的唯一改变的方法就是触发,是一个用于描述已发生事件的普通对象。没有特殊情况没有副作用,没有请求没有变量修改,只进行单纯执行计算。 系列文章: Redux 入门(本文) Redux 进阶 番外篇: Vuex — The core of Vue application 状态管理,第一次听到这个词要追溯到去年年...

    shusen 评论0 收藏0
  • redux —— 入门实例 TodoList

    摘要:入门实例前端技术真是日新月异,搞完不搭配个数据流都不好意思了。关于的用法,这只是基础入门的部分,还有的多的搞基操作,比如异步数据流和配合。 redux —— 入门实例 TodoListshowImg(https://segmentfault.com/img/bVtSeH); Tip 前端技术真是日新月异,搞完 React 不搭配个数据流都不好意思了。满怀期待的心去翻了翻 flux,简直...

    SKYZACK 评论0 收藏0
  • Redux技术架构简介(二)-- 异步实现

    摘要:异步实现设计需要增加三种通知异步请求发起的异步请求成功的异步请求失败的示例代码如下返回参数完全可以自定义。这种分别在请求开始前,请求成功后,请求失败后发送。表示数据的有效性,他的作用是在异步请求发送失败后,告诉当前的数据是过时的数据。 说明:对Redux不了解的同学可先看看这篇文章Redux技术架构简介(一) 前言 这里说的Redux异步实现,是专指Redux中的异步Action实现,...

    wuaiqiu 评论0 收藏0
  • Redux:Middleware你咋就这么难

    摘要:接下来的函数就有点难度了,让我们一行一行来看。上面实际的含义就是将数组每一个执行的返回值保存的数组中。需要注意的是,方法返回值并不是数组,而是形如初始值的经过叠加处理后的操作。从而实现异步的。   这段时间都在学习Redux,感觉对我来说初学难度很大,中文官方文档读了好多遍才大概有点入门的感觉,小小地总结一下,首先可以看一下Redux的基本流程:showImg(https://segm...

    superPershing 评论0 收藏0

发表评论

0条评论

brianway

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<