前言
在 Vue 生态中, Vuex 这个官方的状态管理库在 Vue 应用开发中,为我们带来了非常便捷的功能。但是 Vuex 20K+ 的大小,也带来了一些成本,对于项目规模较小的应用来说, 引入 Vuex 只是为了存储用户信息之类的一小撮数据,有点不值得。 Vue2.2.x 在后期就提供了 provide/inject API 来帮我们实现跨层级组件之间的通信。
Vue3.x 把 provide 也放到了应用 API 上,这就更方便让我们在此基础上,实现一个基础的状态管理。
如何通过 provide/inject 实现 Vuex的功能
首先我们想一下大概的逻辑,把它做成一个插件,通过 use 方法注册到应用实例中。
在 install 方法中,通过 app.provide 方法,把数据挂载到根组件上,该数据应该是一个响应式数据,并且为了数据安全,应该对数据的变更进行限制,遵循单向数据流的设计,不能让用户直接的进行修改,所以在暴露数据时,应该对数据进行 readonly(只读) 处理。
实现类似 Vuex 的 useStore 功能,让用户通过此方法访问数据。
实现类似 Vuex 的 mapState、mapMutations 和 mapActions方法,简化操作。
用法直接跟 Vuex 一样。
在应用中注册此插件
//main.tsimport{createApp}from'vue'importAppfrom'./App.vue'importrouterfrom'./router'importstorefrom'./store'constapp=createApp(App)app.use(router).use(store).mount('#app')
插件的入口文件
在入口文件中,直接导出所有方法。
//sky-vuex/index.tsexport*from'./main/index'
创建 store ,把对应的数据挂载到根组件上
store 本身是一个对象,包含 state 属性和 commit、dispatch 等方法。 store 最主要的一些功能就是让所有组件,都能拿到 store 对象,来获取 state 中的数据,以及调用相关方法来修改 state。
//sky-vuex/main/index.tsimport{inject,reactive,readonly}from'vue'constmainStoreSky=Symbol('mainstorekey')interfacestoreOptions{state?:anyactions?:anymutations?:any}exportconstcreateStore=(options:storeOptions={})=>{//创建store对象constinitOptions={state:{},actions:{},mutations:{},}constmergeOptions:storeOptions=Object.assign(initOptions,options)conststate=reactive(mergeOptions.state)conststore={state:readonly(state),dispatch(eventName:string,...args:any[]){mergeOptions.actions[eventName](store,...args)},commit(eventName:string,...args:any[]){...},}return{install(app:any){app.provide(mainStoreSky,store)},}}exportconstuseStore=():any=>{//其他组件通过此方法,获取store对象returninject(mainStoreSky)}
实现 mapState、mapMutations 和 mapActions方法
exportconstmapState=()=>{conststore=useStore()returnstore.state}exportconstmapActions=(eventName:string)=>{conststore=useStore()return(...args:any[])=>store.dispatch(eventName,...args)}exportconstmapMutations=(eventName:string)=>{conststore=useStore()return(...args:any[])=>store.commit(eventName,...args)}
组件中使用
//store/index.tsimport{createStore}from'../sky-vuex/index'exportdefaultcreateStore({state:{age:18},mutations:{setAge(state:any,data:number){state.age=data}},})
//Home.vue<template><divclass="home"><button@click="handleAge(23)">修改数据</button><h1>{{state.age}}</h1></div></template><scriptlang="ts">import{defineComponent}from'vue'import{useStore,mapActions,mapMutations}from'@/sky-vuex/index'exportdefaultdefineComponent({name:'Home',setup(){conststore=useStore()consthandleAge=mapMutations('setAge')//consthandleAge=mapActions('setAge')//consthandleAge=()=>{//store.dispatch('setAge',5)//}return{state:store.state,handleAge,}},})</script>
总结
至此已经实现了基础的 Vuex 功能,可以自己动手实践一下,进行优化,有问题欢迎大家提出。