vuex
什么是Vuex
概念:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
简单点来说(说人话),就是实现任意组件中通信,并可以检测数据的变化。
vuex原理
Vuex是集中于MVC模式中的Model层,规定所有的数据操作必须通过 action - mutation - state 的流程来进行,再结合Vue的数据视图v-moder等双向绑定特性来实现页面的展示更新。
简述主要方法详情:
- Vue Components:Vue组件。展示页面,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。
- dispatch:操作行为触发方法。是唯一能执行action的方法。
- actions:操作行为处理模块。处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。
- commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
- mutations:状态改变操作方法。是Vuex修改state的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。
- state:页面状态管理容器对象。集中存储Vue components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。
Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。这里就不过多介绍了,看官方文档(Module | Vuex (vuejs.org))
总的一句话简述就是:
Vue组件接收交互行为,调用dispatch方法触发action相关处理,若页面状态需要改变,则调用commit方法提交mutation修改state,通过getters获取到state新值,响应数据或状态给Vue 组件,界面随之更新。
Redux
问题
对于中间件的词middleware的概念并不陌生,相对于 Express 或者 Koa 的 middleware,Redux middleware 被用于解决不同的问题,但其中的概念是类似的。它提供的是位于 action 被发起之后,到达 reducer 之前的扩展点。 你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。
中间件从何而来,为什么要使用中间件,他的核心思想是什么,等一系列面试问题接踵而来。
我们常在使用的中间件,如redux-thunk,redux-promise,redux-saga等处理异步的中间件它们是如何被加入到redux生命周期里去的,他们是如何增强 state/dispatch 的,等这些都归功于redux的一个api叫applyMiddleware。
1. 为什么要使用中间件
从redux官方可以得知,redux团队以记录日志和创建崩溃报告为例,手动记录日志开始的7个案例,从崩溃到解决,最终促使middleware的诞生
2. 中间件做了什么
核心就是在 action 被发起之后,到达 reducer 之前的一些扩展
主要增强store.dispatch的能力
3. 核心思想
实现核心compose组合执行中间件
组合函数compose是借助于es6的Array.prototype.reduce方法实现
/**
* compose源码
*/
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
// a为上次中间件执行函数在外层,b为当前中间件函数在里层,也就实现从右往左执行
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
参数…funcs即为中间件函数,如果没有返回空函数v=>v,如果有一个返回第一个中间件函数,如果有多个则返回层级嵌套中间件函数,从右往左执行,右边函数的执行结果作为左边函数的执行参数
applyMiddleware 实现
首先从调用入口开始 createStore.js 部分
/**
* createStore部分源码
*/
export default function createStore(reducer, preloadedState, enhancer) {
// 省略一些参数类型判断
// 此处判断将enhancer挪位,可以实现将enhancer参数放在第二个位子
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
// 关键代码
return enhancer(createStore)(reducer, preloadedState)
}
}
关键代码解读:
- enhancer即为中间件函数 如:applyMiddleware(thunk, logger)
由上文中间件组合函数compose得知applyMiddleware(thunk, logger)的执行结果为a(b(…args))的组合函数的形式 - 第二步传入createStore作为中间件组合函数的参数并执行
- 第三步即为使用(中间件增强后的…store/dispach方法)来解析reducer
进入applyMiddleware部分
/**
* applyMiddleware源码
*/
export default function applyMiddleware(...middlewares) {
// createStore即为上文第2步传入的参数
return createStore => (...args) => {
// 执行createStore生成store
const store = createStore(...args)
let dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
)
}
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
// 将每个中间件带上 middlewareAPI 参数并返回新数组
const chain = middlewares.map(middleware => middleware(middlewareAPI))
// 执行compose中间件组合函数(将store.dispatch作为参数)
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
结语
任何框架或库的中间件都是为了提供给用户一个可配置执行额外逻辑代码的勾子,是一种enhancer
看懂了redux中间件的原理,学习其他框架的中间件可更为轻松!