基础篇六 Nuxt4 状态管理:useState 的正确用法
文章目录一、useState 基础二、跨组件共享三、封装成 Composable四、用户状态管理五、购物车状态六、持久化存储七、SSR 注意事项八、useState vs Pinia总结个人网站组件间共享数据是前端开发的常见需求。Vue 2 时代我们用 VuexVue 3 有了 Pinia但 Nuxt 提供了一个更轻量的内置方案——useState。今天我们来学习它的正确用法。一、useState 基础useState是 Nuxt 内置的状态管理工具可以在任何组件中使用script setup langts // 创建一个响应式状态 const count useState(count, () 0) // 或者用 ref但 useState 跨组件共享 const countRef ref(0) /script template div p计数: {{ count }}/p button clickcount1/button /div /templateuseState和ref的区别ref是组件内部的切换页面就销毁useState是全局的组件间共享SSR 时数据还能传递二、跨组件共享多个组件可以访问同一个状态只需相同的 key!-- components/Counter.vue -- script setup langts const count useState(count, () 0) /script template div p计数: {{ count }}/p button clickcount1/button /div /template!-- components/CounterDisplay.vue -- script setup langts // 相同 key共享同一状态 const count useState(count) /script template p当前计数: {{ count }}/p /template!-- pages/index.vue -- template div Counter / CounterDisplay / /div /template两个组件共享同一个count一个修改另一个自动更新。三、封装成 Composable更好的做法是封装成composable// composables/useCounter.tsexportconstuseCounter(){constcountuseStatenumber(count,()0)constincrement()count.valueconstdecrement()count.value--constreset()count.value0return{count,increment,decrement,reset}}使用script setup langts const { count, increment, decrement, reset } useCounter() /script template div p{{ count }}/p button clickincrement/button button clickdecrement-/button button clickreset重置/button /div /template好处逻辑封装复用方便类型安全有完整提示修改时只需改一处四、用户状态管理最常见的场景是存储用户信息// composables/useUser.tsinterfaceUser{id:numbername:stringemail:stringavatar:string}exportconstuseUser(){constuseruseStateUser|null(user,()null)constisLoggedIncomputed(()!!user.value)constloginasync(email:string,password:string){constresponseawait$fetch(/api/login,{method:POST,body:{email,password}})user.valueresponse.user}constlogoutasync(){await$fetch(/api/logout)user.valuenull}constfetchUserasync(){try{constresponseawait$fetch(/api/user)user.valueresponse.user}catch{user.valuenull}}return{user,isLoggedIn,login,logout,fetchUser}}使用script setup langts const { user, isLoggedIn, login, logout } useUser() /script template div v-ifisLoggedIn img :srcuser?.avatar :altuser?.name / span{{ user?.name }}/span button clicklogout退出/button /div div v-else NuxtLink to/login登录/NuxtLink /div /template五、购物车状态// composables/useCart.tsinterfaceCartItem{id:numbername:stringprice:numberquantity:number}exportconstuseCart(){constitemsuseStateCartItem[](cart,()[])consttotalcomputed(()items.value.reduce((sum,item)sumitem.price*item.quantity,0))constitemCountcomputed(()items.value.reduce((sum,item)sumitem.quantity,0))constaddItem(product:OmitCartItem,quantity){constexistingitems.value.find(itemitem.idproduct.id)if(existing){existing.quantity}else{items.value.push({...product,quantity:1})}}constremoveItem(id:number){constindexitems.value.findIndex(itemitem.idid)if(index-1){items.value.splice(index,1)}}constupdateQuantity(id:number,quantity:number){constitemitems.value.find(itemitem.idid)if(item){item.quantityMath.max(0,quantity)if(item.quantity0){removeItem(id)}}}constclear(){items.value[]}return{items,total,itemCount,addItem,removeItem,updateQuantity,clear}}六、持久化存储默认情况下页面刷新状态会丢失。结合localStorage实现持久化// composables/usePersistentState.tsexportconstusePersistentStateT(key:string,defaultValue:T){conststateuseStateT(key,(){// 客户端从 localStorage 读取if(import.meta.client){conststoredlocalStorage.getItem(key)if(stored){try{returnJSON.parse(stored)}catch{returndefaultValue}}}returndefaultValue})// 监听变化同步到 localStoragewatch(state,(value){if(import.meta.client){localStorage.setItem(key,JSON.stringify(value))}},{deep:true})returnstate}使用// composables/useCart.tsexportconstuseCart(){// 使用持久化状态constitemsusePersistentStateCartItem[](cart-items,[])// ...其他逻辑}七、SSR 注意事项useState支持 SSR但有几点要注意不要在 setup 外使用// ❌ 错误constglobalCountuseState(count)// 在模块顶层exportdefaultdefineNuxtConfig({})// ✅ 正确exportconstuseCounter(){constcountuseState(count)// 在函数内部return{count}}避免使用 Date.now() 等不确定值// ❌ 可能导致 hydration 不匹配consttimestampuseState(ts,()Date.now())// ✅ 使用固定的初始值consttimestampuseState(ts,()0)服务端数据会自动传递给客户端exportconstuseUser(){constuseruseState(user,()null)// 服务端获取数据if(import.meta.server){consteventuseRequestEvent()user.valueevent.context.user}// 客户端自动拿到服务端的数据return{user}}八、useState vs Pinia什么时候用useState什么时候用 Pinia对比项useStatePinia学习成本低中功能复杂度简单强大开发工具无有 DevTools插件生态无丰富适用场景简单状态复杂应用建议小项目、简单状态useState大项目、复杂状态管理Pinia两者可以混用总结useState核心用法功能示例创建状态useState(key, () defaultValue)获取状态useState(key)封装逻辑放到composables/useXxx.ts持久化结合localStorage下一篇聊聊 Pinia 集成学习更强大的状态管理方案。相关文章入门篇三Nuxt4组件自动导入写代码少敲一半字入门篇二Nuxt 4路由自动生成告别手动配置路由的日子延伸阅读nuxt4完整系列持续更新中。。欢迎来逛逛内容有帮助点赞、收藏、关注三连评论区等你