一、useState - Nuxt3中的全局状态管理

1. 介绍

这是Nuxt3为我们准备的全局状态管理,且支持响应式,可以无需使用pinia等,直接在项目中使用。

官网文档useState · Nuxt Composables 、 State Management · Get Started with Nuxt

注意事项

· 由于会把State存储为JSON,所以请不要存储不能被JSON化的数据,比如类、函数、Symbol等

· 为了让我们的状态管理能在任何地方使用(不止在setup中),最好统一使用函数的写法,见下

2. 基本使用

· 创建文件

在根目录下的 /composables 文件夹中新建文件state.ts  (没有这个文件夹就新建,为什么放在这个文件夹,是因为这个文件夹里导出的函数,Nuxt会帮我们自动引入,官网文档: composables/ · Nuxt Directory Structure

· 创建需要全局共享的变量并导出

统一一下命名:导出的函数的格式为 useXxx

讲解一下 useState 函数的用法

第一个参数是全局唯一的键值(就比如你这个变量想叫什么名字),如下方代码中的 ‘color’和‘people’(千万不要出现重复的键值)

第二个参数是该状态的值,用函数形式表达,比如下方的 ()=>‘red’,实际的值就是 ‘red’ 。

然后整个useState 作为一个箭头函数的返回值,赋值给 useXxx  (为了能在任意地方都能使用state)

 1// state.ts
 2 
 3/**简单数据类型示例 */
 4export const useColor = () => useState<string>('color', () => 'red')
 5 
 6 
 7/**复杂数据类型示例 */
 8interface test{
 9    /**姓名 */
10    name: string,
11    /**年龄 */
12    age: number
13    /**数组 */
14    arr: number[]
15}
16export const usePeople = () =>  useState<test>('people',()=>({ //箭头函数return对象时的简写
17    name: '小明',
18    age: 18,
19    arr: [1,2]
20}))

· 使用(展示)

在任意想使用全局状态的文件中(不止.vue文件),输入  const color = useColor()

在JS / TS代码中, color.value即可获取color真正的值 (和vue3中的ref数据使用方法一模一样)

在template模板中,直接 {{ color }} 即可,无需 .value (和vue3中的ref数据使用方法一模一样)

 1<template>
 2    <div>{{ color }} </div>
 3    <div>{{ people.name}} </div>
 4</template>
 5 
 6<script setup lang='ts'>
 7//直接使用下面这俩函数,无需导入,因为Nuxt帮我们导入了
 8const color = useColor() 
 9const people = usePeople()
10 
11//在js代码中使用
12const func = ()=>{
13    if(color.value === 'red'){
14        console.log('是红色')
15    }
16}
17 
18</script>

· 使用(修改)

在任意地方都能修改(不止.vue文件)。 示例见下**: (和vue3中的ref数据使用方法一模一样)**

下面的修改方法都能触发页面的响应式

 1//直接使用下面这俩函数,无需导入,因为Nuxt帮我们导入了
 2const color = useColor() 
 3const people = usePeople()
 4 
 5//在js代码中修改
 6color.value = 'black' //简单数据类型直接.value修改
 7people.value.name = '小黑'  //复杂数据类型可以像这样一个个属性修改
 8people.value = { //也可以像这样直接赋值新对象,反正都能响应式
 9  name: '小黑',
10  age: 10,
11  arr: [1,2,3,4]
12}

二、持久化(按需)

上面的数据只是存储在内存中的,当浏览器刷新或者关闭后,重新打开就恢复原样了。很多时候我们需要对数据进行持久化(保存在localStorage中)

注意:由于Nuxt是服务端渲染,localStorage只能在挂载后才能使用!!

下面是我自己写的一种实现持久化的方法,大家也可以自己发挥。只要知道在onMounted后使用就行。

因为不是所有数据都需要持久化,所以我做了一些适配:

只有需要的数据才会持久化,根据函数名自动存储为对应的键放在localStorage中。(比如useColor会变为color存储在localStorage中,usePeople会变为people。但是多驼峰的也会全变为小写,比如useAaaBbb,会变为aaabbb存储,你可以根据需要修改,反正不影响代码运行)

持久化时机:在app挂载时,从localStorage获取数据赋值到State中,在页面将要关闭/刷新时,把State数据放到localStorage中。

 1// state.ts
 2 
 3/**简单数据类型示例 */
 4export const useColor = () => useState<string>('color', () => 'red')
 5/**复杂数据类型示例 */
 6interface test{
 7    /**姓名 */
 8    name: string,
 9    /**年龄 */
10    age: number
11    /**数组 */
12    arr: number[]
13}
14export const usePeople = () =>  useState<test>('people',()=>({
15    name: '小明',
16    age: 18,
17    arr: [1,2]
18}))
19/** 不需要持久化的数据示例 */
20export const useXxx = () => useState<string>('Xxx', () => '我不需要持久化')
21 
22// 下面是持久化相关的代码
23 
24 
25/**需要进行持久化的数据:把需要持久化的数据放在下面这个对象中,才会持久化,不需要持久化的数据就不用放到这里了。 */
26const enduring: { [key: string]: () => Ref<any> } = {
27    useColor, usePeople
28}
29//下面的俩函数在app.vue的onMounted中统一调用,或者在其它情况挂载后单独调用。
30/**把所有指定数据保存到本地存储 
31 * @param key 要保存的数据名。不填的话就是保存全部(一般不填,统一在页面关闭时保存。如果是特别重要的数据,就时不时单独保存一下即可。)
32 */
33export const setLocal = (key?: string) => {
34    if (key) {
35        console.log('只保存', key);
36        const useKey = 'use' + key.slice(0, 1).toUpperCase() + key.slice(1).toLowerCase();//首字母大写,其它全部转小写
37        const func = enduring[useKey]
38        if (!func) {
39            console.log('没有找到', useKey, '对应的函数');
40            return
41        }
42        localStorage.setItem(key, JSON.stringify(func().value))
43    } else {
44        console.log('正在保存全部数据');
45        for (const key in enduring) {
46            if (Object.prototype.hasOwnProperty.call(enduring, key)) {
47                const element = enduring[key];
48                const setKey = key.toLowerCase().substring(3)//去掉前面的use ,其它全部转小写
49                try {
50                    localStorage.setItem(setKey, JSON.stringify(element().value))
51                } catch (error) {
52                    console.log(`在设置${setKey}的数据时出现错误`, error);
53                }
54            }
55        }
56    }
57}
58/**从本地存储获取数据到state中 */
59export const getLoacl = () => {
60    for (const key in enduring) {
61        if (Object.prototype.hasOwnProperty.call(enduring, key)) {
62            const element = enduring[key];
63            const setKey = key.toLowerCase().substring(3)//去掉前面的use ,其它全部转小写
64            try {
65                const localData = localStorage.getItem(setKey) || ''
66                if (localData) {
67                    element().value = JSON.parse(localData)
68                    console.log(setKey, '的本地存储数据获取成功', element().value);
69                }
70            } catch (error) {
71                console.log(`在获取${setKey}的数据时出现错误`, error);
72            }
73        }
74    }
75}

然后在app.vue中,进行下面的操作:   下面的俩函数无需引入,Nuxt自动帮我们引入了

 1<template>
 2  <div class="App">
 3     <!-- 这里是APP.vue !!!!! --> 
 4     <NuxtPage />
 5  </div>
 6</template>
 7<script setup lang="ts"> 
 8//挂载钩子
 9onMounted(() => {//必须在onMounted的时候才能用local和window  
10  getLoacl()
11  window.onbeforeunload = () => {//离开页面时保存数据,由于可能突发情况,所以重要数据请手动调用setLocal函数
12    setLocal() //如果需要调试本地存储数据,记得把这个注释一下
13  }
14})
15</script>

以上就实现了按需持久化数据。注:window.onbeforeunload 是会在页面关闭或刷新时执行,但是意外关闭的浏览器不会执行这个函数,所以重要的数据记得时不时单独调用一下 setLocal(‘xxx’) 函数,保证数据持久化(可以利用watch监听,或者简单粗暴的定时器)

个人笔记记录 2021 ~ 2025