【VueUse】重新定义状态管理在 Vue 中的体验

在 Vue 生态系统中,状态管理一直是开发者们关注的焦点之一。而随着 VueUse 的出现,我们迎来了一种全新的方式来处理状态管理,它让我们能够以更简单、更灵活的方式来管理应用程序的状态。

        在本文中我们将深入探讨 VueUse 中与状态管理相关的内容,从基本的状态响应式到高级的状态管理技巧,以及一些实用的状态管理模式。无论你是刚刚接触 Vue 还是已经是一名经验丰富的 Vue 开发者,本文都将为你带来新的见解和灵感,让你在状态管理的道路上走得更远、更高。

目录

createGlobalState(项目全局状态)

createInjectionState(组件全局状态)

createSharedComposable(封装复用函数)

useAsyncState(异步加载的所有状态)

useLastChanged(获取前后时间差)

useStorage(本地存储数据管理)

useLocalStorage(本地存储空间管理)

useSessionStorage(会话存储空间)

最后总结


createGlobalState(项目全局状态)

将状态保存全局作用域中,以便跨Vue实例复用。什么意思呢?就是实现类似pinia和vuex的功能效果,将数据进行集中状态管理,放在全局上所有的组件都能拿到使用,所有使用这个全局状态的组件都可以共享和修改这个对象。它不需要组件之间的层次结构,可以在任何地方使用。牛犇只能说,如下:

创建一个store文件夹用于存储全局状态数据,借助createGlobalState函数撰写响应式数据,被设置相关的actions和getters函数,并把state和函数return出去。然后在组件中直接使用即可,方法和pinia的写法类似只能说,会pinia使用createGlobalState简直手到擒来!

createGlobalState并没有使用持久化的效果,实现持久化需要再借助另一个API函数,这个后面会讲到,先看看实现的效果吧!非常nice。

createInjectionState(组件全局状态)

创建可以注入到组件中的全局状态。什么意思呢?就是允许在组件之间共享状态,使用类似vue中的 provide / inject API,可以在父组件中创建状态,然后把状态注入到子组件中,子组件来拿到状态数据,这种方式适用于有层次结构的组件之间的状态传递,如下:

我们在仓库中定义一个组件全局状态的函数,我们并不需要给其设置初始值而是通过传参即可:

import { ref, computed } from "vue";
import { createInjectionState } from "@vueuse/shared";

const [useProvideCounterStore, useCounterStore] = createInjectionState((initialValue) => {
    // state
    const count = ref(initialValue)
    // actions函数
    const increment = () => {
      count.value++
    }
    // getters函数
    const double = computed(() => count.value * 2)
    return { count, double, increment }
  })

// 如果要隐藏“useCounterStore”并将其包装在默认值逻辑中或抛出错误逻辑,请不要导出“useCounterStore”
export { useProvideCounterStore, useCounterStore }

接下来我们通过如下的方式进行父子组件状态的传递,仓库只是一个踏板,真正控制数据的还是父组件,如下:

最终达到的效果如下所示:

createSharedComposable(封装复用函数)

让一个钩子函数可用于多个Vue实例中。什么意思呢?就是用于创建共享的组合式函数,将逻辑组织为可重用的函数,以更好地管理组件的复杂性。意义在于创建一个可以在多个组件之间共享状态和逻辑的组合式函数,避免在多个组件中重复编写相同的逻辑,同时也提高了代码的可维护性和可复用性,如下:

我们随便创建个文件,然后写一个共享的函数,注意createSharedComposable参数只能是一个,如果你想返回多个函数的话需将其放在一个函数里面然后return出去即可,这里我们使用了自带的API函数还有自定义一个函数,然后将这两个公共函数return出去:

import { createSharedComposable, useMouse } from '@vueuse/core'
// 自定义函数
const custom = ()=>{
    return [ 1, 2 ]
}
// createSharedComposable必须返回一个函数
export const useSharedMouse =   (()=>{
    return {
        useMouse,
        custom
    }
})

接下来在两个子组件中使用createSharedComposable给我们的共享函数:

然后在父组件中调用这两个子组件即可,发现两个子组件的得到的结果都是一样的,程序复用:

useAsyncState(异步加载的所有状态)

响应式获取异步状态。不会阻塞setup 函数,在promise完成后,将自动触发。什么意思呢?就是为了简化在 Vue 组件中处理异步操作的状态管理。通常情况下,当我们在 Vue 组件中执行异步操作时,需要定义多个状态来表示异步操作的不同阶段(如加载中、成功、失败等),并在组件中进行相应的状态管理和更新。而 useAsyncState 函数可以帮助我们更轻松地管理这些状态。如下:

这里我直接打出 useAsyncState  基本上所有用到的参数,通过注释可以看到每个参数具体的含义

<template>
  <div class="use-async-state">
    接口数据:{{ ajaxData.state }}
    <br><br>
    Ready: {{ ajaxData.isReady ? '准备完毕' : '未准备' }}
    <br>
    Loading: {{ ajaxData.isLoading ? '加载中' : '加载完毕' }}
  </div>
</template>


<script lang="ts" setup>
import { onMounted, reactive, onBeforeMount } from 'vue'
import { useAsyncState } from '@vueuse/core'

const ajaxData = reactive({
  state: '',
  isReady: false,
  isLoading: true,
})

const fetchUser = async() => {
  const resp = await fetch(`https://jsonplaceholder.typicode.com/users/${1}`)
  return resp.json()
}

const { state, isLoading, isReady, error, execute }= useAsyncState(fetchUser, {default: '未加载前的数据'}, {
  // immediate: false, // 默认是true,控制组件加载后立即执行
  delay: 2000, // 默认是0,控制组件加载后多久执行
  onSuccess: () => {
    ajaxData.state = state.value
    ajaxData.isLoading = isLoading.value
    ajaxData.isReady = isReady.value
    console.log('useAsyncState', state.value);
  },
  onError: () => {}, // 错误处理
})

console.log('setup函数中',state.value);
onMounted(()=>{
  console.log('我是挂载后',state.value);
})
onBeforeMount(()=>{
  console.log('我是挂载前',state.value);
})
</script>

我设置了延迟两秒执行获取接口数据,结果如下:

代码中的immediate属性,搭配execute可以手动控制函数的执行,如下:

<template>
  <div class="use-async-state">
    接口数据:{{ ajaxData.state }}
    <br><br>
    Ready: {{ ajaxData.isReady ? '准备完毕' : '未准备' }}
    <br>
    Loading: {{ ajaxData.isLoading ? '加载中' : '加载完毕' }}
    <br />
    <button @click="loadData">重新加载数据</button>
  </div>
</template>


<script lang="ts" setup>
import { onMounted, reactive, onBeforeMount } from 'vue'
import { useAsyncState } from '@vueuse/core'

const ajaxData = reactive({
  state: '',
  isReady: false,
  isLoading: true,
})

const fetchUser = async(id: number) => {
  const resp = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
  return resp.json()
}

const { state, isLoading, isReady, error, execute }= useAsyncState(fetchUser, {default: '未加载前的数据'}, {
  immediate: false, // 默认是true,控制组件加载后立即执行
  delay: 2000, // 默认是0,控制组件加载后多久执行
  onSuccess: () => {
    ajaxData.state = state.value
    ajaxData.isLoading = isLoading.value
    ajaxData.isReady = isReady.value
    console.log('useAsyncState', state.value);
  },
  onError: () => {}, // 错误处理
})

let id = 0

const loadData = () => {
  ajaxData.state = ''
  ajaxData.isReady = false
  ajaxData.isLoading = true
  id+=1
  execute(2000, id) // 执行函数,第一个参数是延迟时间,第二个参数是函数的参数
}

console.log('setup函数中',state.value);
onMounted(()=>{
  loadData()
  console.log('我是挂载后',state.value);
})
onBeforeMount(()=>{
  console.log('我是挂载前',state.value);
})
</script>

最终呈现的效果如下,效果很不错!

useLastChanged(获取前后时间差)

记录最后一次更改的时间戳。什么意思呢?就是跟踪指定的值在最后一次发生改变的时间,这在某些场景下非常有用,比如监控某个状态的变化时间,或者执行一些特定的操作,当值发生改变时,为开发者提供方便的状态管理功能,从而提高开发效率和代码可维护性。如下:

这里我通过useLastChanged获取输入框前后输入数据的时间差:

<template>
  <div class="use-last-changed">
    <input v-model="input" /> <br />
    lastChanged: {{ lastChanged }}
    <br />
    formattedTime: {{ formattedTime }}
  </div>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import { useLastChanged } from '@vueuse/core'

const input = ref('')
const lastChanged = useLastChanged(input)
// 格式化时间的 ref
const formattedTime = ref('')

watch(lastChanged, () => {
  const timestamp = lastChanged.value?.toString()
  const date = new Date(Number(timestamp))
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  const hours = date.getHours()
  const minutes = date.getMinutes()
  const seconds = date.getSeconds()
  // 更新 formattedTime
  formattedTime.value = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
})
</script>

达到的效果如下,总体来说还是不错的api:

useStorage(本地存储数据管理)

响应式 LocalStorage/SessionStorage。什么意思呢?就是它用于在 Vue 组件中管理浏览器本地存储(LocalStorage 或 SessionStorage)的值。通过使用 useStorage,你可以方便地在 Vue 组件中读取、写入和监听本地存储中的数据,而不需要手动处理存储和监听逻辑。这可以帮助你更轻松地在应用程序中实现持久化数据的存储和状态管理。

如下我们对useStorage进行一个最简便的操作演示,默认情况下,useStorage将使用存储中的值,如果它存在就会忽略你传入的默认值。忽略的默认值去访问肯定是未定义的。

最终得到如下的结果,父组件存储的数据是持久化的,修改或删除本地数据,子组件也会发生变化,注意useStorage默认是存储本地存储空间,即localStorage

如果你想采用sessionStorage存储的话,给useStorage传递第三个参数即可,如下:

结果如下,这里不再赘述:

合并默认值:如果你想对原本本地存储的数据和你传递的默认值进行合并的话,可以采用如下的操作,启用mergeDefaault选项,将其设置为true时,它将对对象执行浅合并:

您可以传递一个函数来执行自定义合并(例如深度合并),例如:

const state = useStorage(
  'my-store',
  { hello: 'hi', greeting: 'hello' },
  localStorage,
  { mergeDefaults: (storageValue, defaults) => deepMerge(defaults, storageValue) }
)

自定义序列化

默认情况下,useStorage会根据提供的默认值的数据类型巧妙地使用相应的序列化程序。例如,JSON. stringify/JSON.parse将用于对象,Number.toString/parseFloat用于数字等,还可以提供自己的序列化函数来使用Storage,如下:

import { useStorage } from '@vueuse/core';

// 自定义序列化
const store = useStorage(
  'key',
  '123',
  undefined,
  {
    serializer: {
      read: (v: any) => v ? JSON.parse(v) : null,
      write: (v: any) => JSON.parse(v),
    },
  },
)
console.log(store.value) // 123
store.value = null
console.log(store.value) // null

请注意,当您提供null作为默认值时,useStorage不能从中假定数据类型。在这种情况下,您可以提供自定义序列化程序或显式重用内置序列化程序。

import { StorageSerializers, useStorage } from '@vueuse/core'

const objectLike = useStorage('key', null, undefined, { serializer: StorageSerializers.object })
objectLike.value = { foo: 'bar' }

useLocalStorage(本地存储空间管理)

响应式的 LocalStorage。什么意思呢?就是用于在 Vue 组件中使用本地存储的 Hook。它能够方便地将数据保存在浏览器的本地存储中,并且自动将存储的数据与 Vue 组件中的状态进行同步。

和上面useStorage相比就是这个更具针对性,用法一样:

useSessionStorage(会话存储空间)

响应式SessionStorage。什么意思呢?就是用于在 Vue 组件中使用会话存储的 Hook。与 useLocalStorage 类似,它能够方便地将数据保存在浏览器的会话存储中,并且自动将存储的数据与 Vue 组件中的状态进行同步。

最后总结

createGlobalState:用于在任何组件中共享状态,创建一个全局响应式对象。

createInjectionState:用于在父子组件之间传递状态,通过provide/inject API实现。

createSharedComposable:封装复用函数,多组件共享函数的状态和逻辑。

useAsyncState:简化在 Vue 组件中处理异步操作的状态管理,减少重复的状态管理代码。

useLastChanged:跟踪指定的值在最后一次发生改变的时间。

useStorage:用于在Vue组件中管理浏览器本地存储LocalStorage或SessionStorage的值。

useLocalStorage:利用浏览器的本地存储功能,实现数据的持久化存储和状态管理。

useSessionStorage:将数据保存在会话存储中,实现临时性数据的存储和状态管理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/571737.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第一篇【传奇开心果系列】Python深度学习库技术点案例示例:深度解读深度学习在自动驾驶领域的应用

传奇开心果博文系列 系列博文目录Python深度学习库技术点案例示例系列 博文目录前言一、深度学习在自动驾驶方面的应用介绍二、目标检测和识别示例代码三、路况感知示例代码四、行为预测示例代码五、路径规划示例代码六、自动驾驶控制示例代码七、感知融合示例代码八、高精度地…

基于Springboot的点餐平台

基于SpringbootVue的点餐平台的设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页展示 菜品信息 菜品资讯 购物车 后台登录 用户管理 菜品分类管理 菜品信息管理 …

npm、yarn与pnpm详解

&#x1f525; npm、yarn与pnpm详解 &#x1f516; 一、npm &#x1f50d; 简介&#xff1a; npm是随Node.js一起安装的官方包管理工具&#xff0c;它为开发者搭建了一个庞大的资源库&#xff0c;允许他们在这个平台上搜索、安装和管理项目所必需的各种代码库或模块。 &#…

【网页在线小游戏源码】

网页在线小游戏源码 效果图部分源码领取源码下期更新预报 效果图 部分源码 index.html <!DOCTYPE html> <html> <head> <meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <meta id"viewport" na…

零代码编程:下载的PDF文件自动批量重命名

从arxiv或者一些其他网站下载的PDF文件&#xff0c;标题只是创建时间&#xff0c;看不出里面内容是什么&#xff0c;要一个个打开看非常麻烦。 可以在GPT4中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个编写关于重命名PDF文件的Python脚本的任务&…

Llama-7b-Chinese本地推理

Llama-7b-Chinese 本地推理 基础环境信息&#xff08;wsl2安装Ubuntu22.04 miniconda&#xff09; 使用miniconda搭建环境 (base) :~$ conda create --name Llama-7b-Chinese python3.10 Channels:- defaults Platform: linux-64 Collecting package metadata (repodata.js…

机器学习和深度学习-- 李宏毅(笔记与个人理解)Day22

Day 22 Transformer seqence to seqence 有什么用呢&#xff1f; Encoder how Block work 仔细讲讲Residual 的过程&#xff1f; 重构 Decoder - AutoRegressive Mask 由于是文字接龙&#xff0c;所以无法考虑右边的 info 另一种decoder Encoder to Decoder – Cross Attend…

❤mac使用Idea工具

❤mac使用Idea工具 1、安装 直接跳过&#xff0c;文章有 &#xff08;点击跳转&#xff09; 给自己的mac系统上安装java环境 2、使用 快捷键 Command , 系统首选项 设置Idea连接数据库 打开右侧的database&#xff08;或菜单里&#xff09;连接数据库&#xff0c;根据提…

opencv绘制线段------c++

绘制线段 bool opencvTool::drawLines(std::string image_p, std::vector<cv::Point> points) {cv::Mat ima cv::imread(image_p.c_str()); // 读取图像&#xff0c;替换为你的图片路径 cv::Scalar red cv::Scalar(0, 0, 255); // Red color int thickness 2;// 遍…

Vue3 超前版发布,全面拥抱 JSX/TSX

拥抱 JSX/TSX? 我们都知道 Vue 一直主流是使用 template 模板来进行页面的编写。而就在最近,Vue3 的超前项目 Vue Macros 中,发布了 defineRender、setupComponent、setupSFC 这些新的 API,这代表了,以后 Vue3 有可能可以全面拥抱 JSX/TSX 了!! 说这个新 API 之前,我…

2024江苏省考申论新说刷题系统班

2024江苏省考申论新说刷题系统班&#xff0c;针对江苏省考特色&#xff0c;精准指导考生刷题备考。课程系统全面&#xff0c;深入剖析申论题型&#xff0c;提供实战演练机会。通过科学刷题&#xff0c;考生能迅速提升申论能力&#xff0c;为江苏省考成功上岸打下坚实基础。 下…

LangChain的核心模块和实战

主要模型 LLM:对话模型, 输入和输出都是文本Chat Model: 输入输出都是数据结构 模型IO设计 Format: 将提示词模版格式化Predict: langchain就是通过predict的方式调用不同的模型, 两个模型的区别不大, Chat Model 是以LLM为基础的.Parese: langchain还可以对结果进行干预, 得…

Python检测网页文本内容屏幕上的坐标

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Python 检测网页文本内容屏幕上的坐标 在 Web 开发中&#xff0c;经常需要对网页上的文本内…

STM32标准库ADC和DMA知识点总结

目录 前言 一、ADC模数转换器 &#xff08;1&#xff09;AD单通道 &#xff08;2&#xff09;AD多通道 二、DMA原理和应用 &#xff08;1&#xff09;DMA数据转运&#xff08;内存到内存&#xff09; &#xff08;2&#xff09;DMAAD多同道&#xff08;外设到内存&#x…

pnpm install报错 Value of “this“ must be of type URLSearchParams

执行pnpm install的时候就报错Value of “this” must be of type URLSearchParams 由于之前执行没有出现过这个问题&#xff0c;最近在使用vue3所以使用了高版本的node&#xff0c;怀疑是node版本的问题。 解决&#xff1a; 检查node版本 node -v当前使用的是20.11.0的 修改…

银行业ESB架构:构建安全高效的金融信息交换平台

在金融行业&#xff0c;信息交换是银行业务运作的核心。为了实现不同系统之间的数据交互和业务流程的协同&#xff0c;银行通常采用企业服务总线&#xff08;ESB&#xff09;架构。本文将探讨银行业ESB架构的设计理念、关键技术以及实践经验&#xff0c;帮助银行构建安全高效的…

Matlab|基于元模型优化算法的主从博弈多虚拟电厂动态定价和能量管理

1 主要内容 该程序复现《基于元模型优化算法的主从博弈多虚拟电厂动态定价和能量管理》模型&#xff0c;建立运营商和多虚拟电厂的一主多从博弈模型&#xff0c;研究运营商动态定价行为和虚拟电厂能量管理模型&#xff0c;模型为双层&#xff0c;首先下层模型中&#xff0c;构建…

Golang | Leetcode Golang题解之第47题全排列II

题目&#xff1a; 题解&#xff1a; func permuteUnique(nums []int) (ans [][]int) {sort.Ints(nums)n : len(nums)perm : []int{}vis : make([]bool, n)var backtrack func(int)backtrack func(idx int) {if idx n {ans append(ans, append([]int(nil), perm...))return}…

网络安全新挑战:通用人工智能(AGI)等级保护指南

通用人工智能&#xff08;AGI&#xff09;的发展现状及趋势 随着2023年大语言模型应用的划时代突破&#xff0c;以ChatGPT为杰出代表的此类技术犹如一股洪流&#xff0c;彻底颠覆了人类与机器智能交互的疆界&#xff0c;引领通用人工智能&#xff08;AGI&#xff09;步入一个崭…

GAN详解,公式推导解读,详细到每一步的理论推导

在看这一篇文章之前&#xff0c;希望熟悉掌握熵的知识&#xff0c;可看我写的跟熵相关的一篇博客https://blog.csdn.net/m0_59156726/article/details/138128622 1. GAN 原始论文&#xff1a;https://arxiv.org/pdf/1406.2661.pdf 放一张GAN的结构&#xff0c;如下&#xff1…