useState全局状态管理与localStorage本地存储持久化

2025-04-05
14405 分钟
...

一、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)

// state.ts
 
/**简单数据类型示例 */
export const useColor = () => useState<string>('color', () => 'red')
 
 
/**复杂数据类型示例 */
interface test{
    /**姓名 */
    name: string,
    /**年龄 */
    age: number
    /**数组 */
    arr: number[]
}
export const usePeople = () =>  useState<test>('people',()=>({ //箭头函数return对象时的简写
    name: '小明',
    age: 18,
    arr: [1,2]
}))

· 使用(展示)

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

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

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

<template>
    <div>{{ color }} </div>
    <div>{{ people.name}} </div>
</template>
 
<script setup lang='ts'>
//直接使用下面这俩函数,无需导入,因为Nuxt帮我们导入了
const color = useColor() 
const people = usePeople()
 
//在js代码中使用
const func = ()=>{
    if(color.value === 'red'){
        console.log('是红色')
    }
}
 
</script>

· 使用(修改)

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

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

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

二、持久化(按需)

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

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

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

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

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

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

// state.ts
 
/**简单数据类型示例 */
export const useColor = () => useState<string>('color', () => 'red')
/**复杂数据类型示例 */
interface test{
    /**姓名 */
    name: string,
    /**年龄 */
    age: number
    /**数组 */
    arr: number[]
}
export const usePeople = () =>  useState<test>('people',()=>({
    name: '小明',
    age: 18,
    arr: [1,2]
}))
/** 不需要持久化的数据示例 */
export const useXxx = () => useState<string>('Xxx', () => '我不需要持久化')
 
// 下面是持久化相关的代码
 
 
/**需要进行持久化的数据:把需要持久化的数据放在下面这个对象中,才会持久化,不需要持久化的数据就不用放到这里了。 */
const enduring: { [key: string]: () => Ref<any> } = {
    useColor, usePeople
}
//下面的俩函数在app.vue的onMounted中统一调用,或者在其它情况挂载后单独调用。
/**把所有指定数据保存到本地存储 
 * @param key 要保存的数据名。不填的话就是保存全部(一般不填,统一在页面关闭时保存。如果是特别重要的数据,就时不时单独保存一下即可。)
 */
export const setLocal = (key?: string) => {
    if (key) {
        console.log('只保存', key);
        const useKey = 'use' + key.slice(0, 1).toUpperCase() + key.slice(1).toLowerCase();//首字母大写,其它全部转小写
        const func = enduring[useKey]
        if (!func) {
            console.log('没有找到', useKey, '对应的函数');
            return
        }
        localStorage.setItem(key, JSON.stringify(func().value))
    } else {
        console.log('正在保存全部数据');
        for (const key in enduring) {
            if (Object.prototype.hasOwnProperty.call(enduring, key)) {
                const element = enduring[key];
                const setKey = key.toLowerCase().substring(3)//去掉前面的use ,其它全部转小写
                try {
                    localStorage.setItem(setKey, JSON.stringify(element().value))
                } catch (error) {
                    console.log(`在设置${setKey}的数据时出现错误`, error);
                }
            }
        }
    }
}
/**从本地存储获取数据到state中 */
export const getLoacl = () => {
    for (const key in enduring) {
        if (Object.prototype.hasOwnProperty.call(enduring, key)) {
            const element = enduring[key];
            const setKey = key.toLowerCase().substring(3)//去掉前面的use ,其它全部转小写
            try {
                const localData = localStorage.getItem(setKey) || ''
                if (localData) {
                    element().value = JSON.parse(localData)
                    console.log(setKey, '的本地存储数据获取成功', element().value);
                }
            } catch (error) {
                console.log(`在获取${setKey}的数据时出现错误`, error);
            }
        }
    }
}

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

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

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

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
nuxt2025-10-24
Nuxt 中 process.client 与 import.meta.client 的区别
一、来源与定义 | 对比项 | process.client | import.meta.client | | | | | | 来源 | Nuxt 内置的运行时变量(兼容 Node 风格) | Vite 原生 ESM 构建标志 | | 定义位置 | Nuxt 在构建阶段自动注入到全局 | Vite 在编译阶段静态替换 | | 作用机制 | 运行时判断变量 | 构建时编译宏(静态替换) | | 语法类型 | CommonJS 风格 | E...
学习
nuxt2025-10-22
Nuxt SSR 与 Next.js SSR
🧭 引言 在现代前端生态中, Nuxt(Vue) 与 Next.js(React) 是最成熟的两大全栈框架。 它们都具备 SSR(Server Side Rendering) 能力,但实现原理与运行机制差异巨大。 如果你在使用 Nuxt 构建 SSR 项目,却发现“路由跳转后不再 SSR”, 而在 Next.js 中同样操作却会重新发起服务端渲染——这不是 bug,而是 理念差异 。 本文将详细对比这两种框架的 SSR 行为,帮助你彻...
学习面试
nuxt2025-09-24
nuxt4制作企业官网
SASS 1、引入SASS 2、配置文件目录 可以注入 SCSS 变量或 mixin 到每个 样式块。 推荐使用 而不是 ,因为 会重复加载。 注意路径 是相对于项目根目录。 3、创建2个文件 问题: 如果用 ,变量仍然可以访问,但 mixin 和函数也要全局注入。 不要在 里再 自己的 ,会出现循环依赖。 不能在global.scss写预设变量,会报错 也可以直接写变量,而不通过单独文件: 4、使用 打包SSG 静态文件 1、配置文件...
学习
nuxt2025-04-08
Nuxt3 使用 ElementUI Plus报错问题
&nbsp;解决方式:官方组件需要被包裹一层,如以下示例:
学习
nuxt2025-04-05
nuxt.js安装国际化插件i18n
国际化i18n配置 1. 安装依赖 2. 配置i18n 3. 使用i18n LanguageSwitcher.vue 4. 创建语言文件 /locales/en.ts /locales/zh.ts 在需要国际化的地方通过{{ $t(‘sidebar.right’) }}的形式来使用 运行项目后,可以引入切换按钮进行语言切换 &nbsp; &nbsp; ps:切换语言后需要 才会正确显示
学习
nuxt2025-04-05
Nuxt3实现事件总线EventBus
事件总线 这里我是用得是 这个库, 是一个微型的 EventEmitter 库 安装 在plugins文件夹下建立mitt.ts文件 使用: A页面 B页面
学习

评论

请登录后发表评论

去登录
加载评论中...

目录