Vuex 是不是有点繁琐?

Vuex 是针对 Vue2 来设计的,因为 option API 本身有很多缺点,所以 Vuex 只好做各种补丁弥补这些缺点,于是变得比较“复杂”。

现在 Vue3 推出了Composition API,功能更强大也弥补了之前的缺点,但是 Vuex 4.0 只是兼容了 Vue3,使用风格上似乎没啥变化。

于是乎怎么看怎么别扭,不是说 Vuex 不够强大,Vuex 的 state 也使用了 reactive ,而且也是用 provide/inject 实现注入的,但是没有后续了,Composition API 的其他特性呢?感觉好浪费呀。

虽然也可以基于 Vuex 用 compositionAPI 的方式实现功能,但是总感觉有点大炮打蚊子的感觉。

做一个轻量级状态管理。

按照“自己动手丰衣足食”的原则,我们自己来做一个轻量级的状态管理。

模仿 Vuex 试着实现了一下基本功能,有点理解为啥 Vuex 弄得那么绕了,因为要把操作函数也给包含进去确实有点难度。

那么就轻量到底吧,只包含状态,不包括 mutations、action 这些操作函数。

于是功能变成这个样子:

状态:全局状态、局部状态

功能:初始化状态、指定的组件里注入局部状态、子组件里加载局部状态

缓存功能,就是可以把状态存入localstorage里面保存,以及初始化的时候从localstorage里面加载状态。

缓存功能暂时没有实现,还没想好局部状态的缓存方案。

功能简单,写起来也就容易多了,然后顺便做成插件的形式,便于使用。

// 模仿Vuex写一个简单的数据、状态、缓存管理

import { reactive, provide, inject } from 'vue'   

export default {
// 状态容器
store: {
state: {}, // 全局状态
init: () => {}, // 初始化全局状态
reg: {}, // 注册局部状态
get: {} // 获取局部状态
}, // 用 symbol 做个标识,避免重名
storeFlag: Symbol('VuexDataState'), // 创建安装插件的实例
createStore(info) {
/* info 的结构示例
const _info = {
// 全局状态,在main.js里面注入
global: {
blogState: { // 每个状态都必须是对象,不支持基础类型
aaa: '状态演示'
}
},
// 局部状态,需要手动注入
local: {
dataList() {
return {}
}
},
// 初始化函数,可以从后端、前端等获取数据加入状态
// 注入后被动调用,仅限于全局状态
init(state) {}
}
*/ for (const key in info.global) {
// 把全局状态存入state
this.store.state[key] = reactive(info.global[key])
} for (const key in info.local) {
const localKey = Symbol(key)
// 加上注册函数
this.store.reg[key] = () => {
// 把局部状态变成 reactive 的形式
const state = reactive(info.local[key]())
// 注入
provide(localKey, state)
// 返回状态,
return state
}
this.store.get[key] = () => {
// 把局部状态变成 reactive 的形式
const state = inject(localKey)
// 返回状态,
return state
}
} // 加上初始化函数
if (typeof info.init === 'function') {
this.store.init = info.init
} const _store = this.store
const _storeFlag = this.storeFlag
return {
// 安装插件
install (app, options) {
// console.log('install--我的状态', _store)
// 注入状态,用 symbol 作为标记,避免重名,避免外部直接用 inject 获取
app.provide(_storeFlag, _store)
// 设置模板使用状态
app.config.globalProperties.$state = _store.state
// 调用初始化,给全局状态赋值
_store.init(_store.state)
}
}
}, // 代码里面调用
useStore() {
// 获取全局状态
const { state, reg, get } = inject(this.storeFlag) return {
state, // 返回全局状态
reg, // 注册局部状态的函数,并且返回对应的局部状态
get // 子组件里面获取状态
}
}
}

怎么样,够轻吧,不超过一百行代码,如果去掉注释空行的话,大概也就三十多行吧。

  • reactive, provide, inject

    状态要实现响应性,那当然要做成 reactive 形式的。

    provide、inject 实现注入功能。

  • store

    内部状态容器。

    state:状态

    init:全局状态的初始化的函数

    reg:局部状态的注入函数

    get:获取局部状态的函数

  • storeFlag

    用 symbol 做全局状态的标记,避免重名。是不是有一种高大上的感觉?[狗头]

  • useStore

    是不是眼熟,在代码里面获取全局状态的。

    除了返回全局状态外,还可以返回局部状态的注入函数和获取函数。

    因为使用 symbol 作为key,外部无法获取,所以需要内部提供一个函数。(我不会告诉你我是故意的)

如果想把状态变成只读(readonlyReactive)的形式然后在返回,那么可以在这里操作。

  • 组件里的使用方法
import VueDS from 'vue-data-state' 

const { state, reg, get } = VueDS.useStore()

state // 全局状态

// 父组件注入状态,并且返回局部状态,以便父组件使用
const 局部状态 = reg.局部状态名称() // 子组件获取局部状态
const 局部状态 = get.局部状态名称()
  • createStore

    看着是不是眼熟,功能和 Vuex 的 createStore 是一样的,接收参数创建 store 然后通过插件注入到 vue 的app上面。

    函数返回 install,用于安装插件。

  • _info

    这个没啥用,就是介绍一下参数的属性格式,实现代码的时候看着方便。另外去掉注释就可以做测试用。

  • 第一个for

    遍历全局状态,变成 reactive 挂到 store 里面。

  • 第二个 for

    遍历局部状态,变成注入和获取的函数,挂到 reg 和 get 里面。

    这个 provide 的 key 也采用 symbol 的形式,避免重名。

  • init

    把初始化函数挂上。

  • install

    安装插件,按照 Vue 官网示例,写了这个install。

    对了,我只是把全局状态挂到模板上面了,局部状态没有挂呢。

    局部状态似乎挂不上,还需要再考虑考虑。

先安装资源包

yarn add vue-data-state

定义状态

// /store-ds/index.js
import VuexDataState from 'vue-data-state' export default VuexDataState.createStore({
global: { // 全局状态
userInfo: {
name:'当前登录人'
}
},
local: { // 局部状态
// 数据列表,使用前需要先注册
dataListState() { // 显示博文列表用的状态
return {
findKind: {}, // 查询方式
find: {}, // 查询关键字
page: { // 分页参数
pageTotal: 100,
pageSize: 2,
pageIndex: 1,
orderBy: { id: false }
},
_query: {}, // 缓存的查询条件
isReload: false // 重新加载数据,需要统计总数
}
}
},
// 可以给全局状态设置初始状态,可以是异步操作
init(state) {
setTimeout(() => {
state.blogState.name = 'int里面设置的数据,可以异步'
},3000)
}
})
  • global

    全局状态,每一个状态都必须是对象(包含数组)的形式,不能是基础类型。

    全局状态,会默认注入到根 app 里面。

    状态名称、属性名称可以随意,这里只是举个例子。

  • local

    局部状态,每个状态也必须是对象形式,不会默认注入,需要在父组件里面使用 reg 调用函数才能注入。

    需要使用 return 的形式,原理和 data 一样。Vuex 模块里的 state 也是需要用 return 形式的。

    状态名称、属性名称可以随意,这里只是举个例子。

  • init

    初始化全局状态的函数,可以不设置。

    在main.js里面安装插件时,注入全局状态后 init会被调用,这时候可以给全局状态赋值,支持异步操作。

在main.js 里面使用

这个就和 Vuex 一样了:

main.js

import { createApp } from 'vue'
import store from './store-ds' // 轻量级状态 createApp(App)
.use(store) // 轻量级状态

后续会在个人博客里面试用一下,具体使用的时候,才会发现有没有问题,以及如何改进。

FAQ

  • 传说中的跟踪呢?

    关于跟踪的问题,一直理解的不深刻,因为dev-tool总是安装不上,后来好不容易安装上了,却不工作。所以暂时跳过这个功能。

  • Vuex支持插件,你的这个呢?

    这个说起来有点复杂,简单的说,目前还没有这样的需求,所以就先跳过了,以后需要的话,可以再加嘛。

    要做插件的话也简单,用 watch 对状态做深度监听,然后调用插件钩子就行。

    要不然我为啥要把状态拆开做reactive呢?

  • 不是说不让直接修改状态吗?

    关于这一点也是比较复杂。

    我可以把状态做成只读的,readonlyReactive一下就行,然后再设计 类似 mutations 的方法 来修改状态。

    但是这么做的意义到底是什么呢?

    没有实现跟踪功能,也没用插件,也不知道怎么弄到dev-tool里面去。

    这些都是配套工程,如果没有这些配套工程,只是做一个只读的话,总是感觉怪怪的。

  • 为啥要弄个局部状态?

    这个要从一次讨论说起。

    某天和知乎大神聊天,他说要做一个模块内的共享状态,一开始我还不理解,讨论了半天,感觉大神说的确实在理。

    于是慢慢开始尝试,最后发现确实挺香的。具体的会在后面的博客项目里面介绍。

  • 支持 option API吗?

    一开始忘记这个事了,后来才想起来,因为是专门针对composition API来设计的,所以应该是不支持的吧。

源码

https://gitee.com/naturefw/vue-data-state

在线演示

https://naturefw.gitee.io/vue-data-state/

制作一个轻量级的状态管理插件:Vue-data-state的更多相关文章

  1. 前端MVC Vue2学习总结(九)——Vuex状态管理插件

    一.概要 1.1.Vuex定义与注意事项 Vuex是为vue.js框架更好的管理状态而设计一个插件.Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的 ...

  2. 利用HttpWebRequest模拟表单提交 JQuery 的一个轻量级 Guid 字符串拓展插件. 轻量级Config文件AppSettings节点编辑帮助类

    利用HttpWebRequest模拟表单提交   1 using System; 2 using System.Collections.Specialized; 3 using System.IO; ...

  3. 推荐一个 Laravel admin 后台管理插件

    如何优雅的写代码,我想是每位程序员的心声.自从15年初第一次接触 Laravel 4.2 开始,我就迷上使用 Laravel 框架了.我一直都想找个时间好好写写有关 Laravel 的使用文章,由浅入 ...

  4. C#-用Winform制作一个简单的密码管理工具

    为什么要做? 首先是为了练习一下c#. 想必大家都有过记不起某个平台的账号密码的经历,那种感受着实令人抓狂.那这么多账号密码根本记不住!我之前用python写过一个超级简单(连账号信息都写在代码里那种 ...

  5. JQuery 的一个轻量级 Guid 字符串拓展插件.

    (function ($) { function guid(g) { var arr = new Array(); //存放32位数值的数组 if (typeof (g) == "strin ...

  6. 结合 Vuex 和 Pinia 做一个适合自己的状态管理 nf-state

    一开始学习了一下 Vuex,感觉比较冗余,就自己做了一个轻量级的状态管理. 后来又学习了 Pinia,于是参考 Pinia 改进了一下自己的状态管理. 结合 Vuex 和 Pinia, 保留需要的功能 ...

  7. vue3 自己做一个轻量级状态管理,带跟踪功能,知道是谁改的,还能定位代码。

    上一篇 https://www.cnblogs.com/jyk/p/14706005.html 介绍了一个自己做的轻量级的状态管理,好多网友说,状态最重要的是跟踪功能,不能跟踪算啥状态管理? 因为vu ...

  8. Vue学习日记(四)——Vue状态管理vuex

    前言 先说句前话,如果不是接触大型项目,不需要有多个子页面,不使用vuex也是完全可以的. 说实在话,我在阅读vuex文档的时候,也很难以去理解vuex,甚至觉得没有使用它我也可以.但是直到我在项目碰 ...

  9. vue创建状态管理(vuex的store机制)

    1:为什么说要是永远状态管理 在使用 Vue 框架做单页面应用时,我们时常会遇到传值,组件公用状态的问题.(子父间传值文章传送门) ,如果是简单的应用,兄弟组件之间通信还能使用 eventBus 来作 ...

随机推荐

  1. 水墨屏开发设备,旧 Kindle 改造而成

    原文地址:Turning an old Amazon Kindle into a eink development platform 原文作者:adq 译者 & 校正:HelloGitHub- ...

  2. Django框架admin后台管理和用户端静态文件

    目录 一.admin后台管理 1. 如何使用 2. 路由分发的本质 二.用户上传的静态文件的展示 1. media配置 2. 手动开设media接口 三.图片防盗链 一.admin后台管理 djang ...

  3. Docker 搭建nexus私服

    一.概述 有三种专门的Maven仓库管理软件可以用来帮助大家建立私服:Apache基金会的Archiva.JFrog的Artifactory和Sonatype的Nexus.而Nexus是当前最流行的M ...

  4. JavaWeb实现用户登录注册功能实例代码(基于Servlet+JSP+JavaBean模式)

    一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp ...

  5. nacos服务注册与发现之客户端

    服务注册 1.1 NamingService.registerInstance的方法为客户端提供的服务注册接口 1.2 客户端通过调用NamingService.registerService上报到n ...

  6. [MIT 18.06 线性代数]Intordution to Vectors向量初体验

    目录 1.1. Vectors and Linear Combinations向量和线性组合 REVIEW OF THE KEY IDEAS 1.2 Lengths and Dot Products向 ...

  7. 你好,布尔玛!(BulmaRazor)

    Blazor 官方简介 Blazor 是一个使用 .NET 生成交互式客户端 Web UI 的框架: 使用 C# 代替 JavaScript 来创建信息丰富的交互式 UI. 共享使用 .NET 编写的 ...

  8. MySQL基础知识:启动管理和账号管理

    整理.记录常用的MySQL基础知识:时间久了,很多就忘记了. 操作系统环境为MacOS Catalina, MySQL版本为: 8.0.13 MySQL Community Server - GPL. ...

  9. AI人脸匹对

    人脸匹对 技术 调用到百度的AI接口,layui的图片上传,栅格化布局 核心代码 纯py代码运行 # encoding:utf-8 from aip import AipFace import bas ...

  10. Java线程安全问题

    线程安全问题是一个老生常谈的问题,那么多线程环境下究竟有那些问题呢?这么说吧,问题的形式多种多样的,归根结底的说是共享资源问题,无非可见性与有序性问题. 1. 可见性 可见性是对于内存中的共享资源来说 ...