Vue3中无需引入Vuex的替代方案

Vue3 中所提供组合 API、ref、reactive、provide、inject几大特性,可以支持完成全局状态管理能力,Vuex 是为 Vue 单独提供的状态管理插件,相对比较笨重,如果项目简单可以尝试替代

所属分类 WEB

相关标签 VueVuex状态

方案说明

在研读 Vue3 的指导文档的时候,我们会被反复提醒重大变化就是提供了组合式 API。

简单来说通过组合式 API,我们可以将 Vue 视图所依赖的数据和逻辑剥离出来。

而我们以前处理数据时,除了当前组件的数据还会有父组件传入的数据,以及使用 Vuex 进行管理的全局数据。

在官方文档中着重提供了一个父组件调用子组件的数据传递和响应性的 DEMO,我的第一反应就是这个方案完全可以替代 Vuex 进行全局状态管理。

PS:不知道为什么,官方没有提到这一点。或许并不推荐或害怕滥用行为?

思路梳理

考虑进行替代之前,我们需要梳理下全局状态管理能力的要点(可以参考 Vuex 的实现)。

  1. 全局访问(state):一个数据源所有的组件都能够访问读取。
  2. 全局更新(getters):当数据源产生变化时,所有组件都能够获取更新后的数据。
  3. 可控修改(mutations):既要能够随时随地被修改,又要能够可控的被修改。

我们需要看在 Vue3 中能够提供这些特性:

  1. 全局访问:在根组件中通过 provide 提供数据,在任意子组件中通过 inject 即可获取到相应的数据。
  2. 全局更新:在根组件中提供的数据通过 ref、reactive 修饰后返回的 Proxy 对象为响应式变量,当其产生变化后,组件会被重新渲染。
  3. 可控修改:在根组件中通过 provide 提供的数据利用 readonly 修饰,禁止外部直接修改,通过根组件将修改方法提供出来供调用。

既然我们发现全局状态管理的诉求在 Vue3 中能够充分实现,那就开始尝试吧。

我们单独规划一个目录用于创建全局数据,比如我放在 src/context 路径下。

其中用户全局数据放在 src/context/user.js,本文主要是提供方案,没有写过多的复杂逻辑。

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

// 用户全局变量命名
const UserSymbol = 'USER'
// 用户全局变量(建立为响应式变量)
const user = reactive({ name: '333', authKeys: [] })
// 用户变量修改方法
const login = ( loginInfo ) => { user.name = loginInfo }

// 用户全局数据提供方法
export const userProvide = () => {
  // 提供一个只读的变量和修改方法
  provide( UserSymbol, {user: readonly(user), login} )
}

// 用户全局数据注入方法
export const userInject = () => {
  return inject(UserSymbol)
}

在 src/context/index.js 对用户全局数据统一管理,因为我们未来还会有其他类型或者模块的数据。

// 导入用户模块全局数据
import { userProvide, userInject } from './data/user'
// 导出相关的注入方法
export { userInject }
// 导出相关的提供方法
export const contextProvider = () => {
    userProvide()
}

App.vue 作为根组件,依照概念我们在根组件中提供的数据,整个应用的其他组件都是子组件,自然可以自由访问数据。

// 导入全局上下文方法
import { contextProvider } from './context'
import HelloWorld from './components/HelloWorld.vue'
export default {
  name: 'App',
  setup() {
    // 根组件注册全局上下文
    contextProvider()
  },
  components: {
    HelloWorld
  }
}

HelloWorld 子组件中尝试读取数据。

<template>
  <div class="hello">
    <h1>以下为子组件</h1>
    <h1>{{ user.name }}</h1>
  </div>
</template>

<script>
import { userInject } from '/src/context'
export default {
  name: 'HelloWorld',
  setup() {
    const { user } = userInject()
    return { user }
  }
}
</script>

结果可以成功读取到 user.name 为 333,因此整个流程是畅通的,我们成功完成了【特性1全局访问】。

我们在子组件中导出了 user,上文我们说过为了确保可控的修改,导出的数据时只读的,我们编写一个方法尝试修改下。

<template>
  <div class="hello">
    <h1>以下为子组件</h1>
    <h1>{{ user.name }}</h1>
    <el-button type="primary" @click="setName()">我来修改</el-button>
  </div>
</template>

编写一个方法 setName() 如下:

  methods:
  {
    setName() {
        // user 是只读的,理论上我们无法修改
        this.user.name = Math.ceil(Math.random()*1000) + ''
    }
  }

尝试修改,确实无法修改,报错如下:

image-20210715152820075

回顾我们在定义全局数据时,不仅导出了数据,同时暴露一个修改方法,这个方法就是用于修改数据的。

因此我们修改子组件 HelloWorld.vue 如下:

<template>
  <div class="hello">
    <h1>以下为子组件</h1>
    <h1>{{ user.name }}</h1>
    <el-button type="primary" @click="setName()">我来修改</el-button>
  </div>
</template>

<script>
import { userInject } from '/src/context'
export default {
  name: 'HelloWorld',
  setup() {
    // 注入修改方法
    const { user, login } = userInject()
    return { user, login }
  },
  methods:
  {
    setName() {
      // 调用提供的修改方法
      this.login(Math.ceil(Math.random()*1000) + '')
    }
  }
}
</script>

image-20210715153245800

自此,我们完成了【特性2全局更新】【特新3可控修改】。

通过上方的样例,我们基本可以确认,Vue3 自身就能够实现全局状态管理,可以尝试用来替代 Vuex 吧。

米虫

做一个有理想的米虫,伪全栈程序猿,乐观主义者,坚信一切都是最好的安排!

本站由个人原创、收集或整理,如涉及侵权请联系删除

本站内容支持转发,希望贵方携带转载信息和原文链接

本站具有时效性,不提供有效、可用和准确等相关保证

本站不提供免费技术支持,暂不推荐您使用案例商业化

发表观点

提示

昵称

邮箱

QQ

网址

当前还没有观点发布,欢迎您留下足迹!

同类其他

WEB

nvm管理node.js和npm多版本切换

在业务中我们会出现不同的项目依赖与不同版本的 node.js,总不能每次跑项目的时候都去重新安装对应版本的 node.js 和依赖,使用 nvm 可以让多个版本的 node.js 共存,并提供管理和切换

Jquery中bind()、live()、delegate()和on()的区别

自Jquery1.7起,on()方法是 bind()、live()、delegate() 方法的新的替代品,我们推荐使用on()来处理业务中的事件绑定,通过理解这些方法的差异能够更加清晰明白使用on()方法的优势所在

Jquery.bind()实现前端字段公共校验器

严谨的页面开发需要着重关注前台校验相关的内容,确保请求参数的合法以保证服务器安全,界面参数众多需要建立一个公共方法,公共校验器的核心方法是Jquery.bind()

Jquery+CSS轻松实现导航动态显示隐藏

绝大多数网站都会有个顶部导航,对于手机端而言为了便于访问导航常常会做固顶操作,通过CSS样式配合Jquery的scroll()方法或原生JS监听滑动事件方法,可以轻松实现下滑隐藏,上滑显示的效果

前端JS对字段编码预防XSS攻击

跨站脚本攻击是比较严重的一种攻击行为,恶意脚本注入到相关页面字段中轻易获取敏感信息和向后端发起请求,前端应用应当对请求数据进行编码

SVGInject插件动态加载SVG并自定义样式

HTML 中加载 SVG 有很多种方式,但如果需要在 HTML 中通过 CSS 样式自由控制 SVG 样式就必须将 svg 标签插入网页找那个成为 DOM 的一部分,本文借助 SVGInject 插件可以快速完成这一操作

选择个人头像

昵称

邮箱

QQ

网址

评论提示

  • 头像:系统为您提供了12个头像自由选择,初次打开随机为你选择一个
  • 邮箱:可选提交邮箱,该信息不会外泄,或将上线管理员回复邮件通知
  • 网址:可选提交网址,评论区该地址将以外链的形式展示在您的昵称上
  • 记忆:浏览器将记忆您已选择或填写过得信息,下次评论无需重复输入
  • 审核:提供一个和谐友善的评论环境,本站所有评论需要经过人工审核