Nuxt3中使用useState时为何有时可省略.value,有时不可?
Nuxt3中useState封装到Composable后模板类型异常的原因与解决方法
问题重现
直接在<script setup>中使用useState时,模板表现符合预期:
<script setup> const num = useState('num', () => 1); </script> <template> <div>{{ num }}</div> <div>{{ typeof num }}</div> <div>{{ JSON.stringify(num) }}</div> </template>
输出:
1 number 1
但将useState封装到composable后,模板中出现异常:
// composables/useNum.js export const useNum = () => { const num = useState('num', () => 1); return { num }; };
组件调用:
<script setup> const numStore = useNum(); </script> <template> <div>{{ numStore.num }}</div> <div>{{ typeof numStore.num }}</div> <pre>{{ JSON.stringify(numStore.num, null, 2) }}</pre> </template>
输出:
1 object { "__v_isShallow": false, "dep": { "w": 0, "n": 0 }, "__v_isRef": true, "_rawValue": 1, "_value": 1 }
原因分析
这是Vue的**自动脱ref(unref)**机制导致的差异:
- 在
<script setup>中,顶层声明的Ref/Reactive对象会被自动处理,模板里直接访问变量名时,会自动读取.value获取内部值,typeof和JSON.stringify也会作用于这个值。 - 但当Ref对象被包裹在普通对象中从composable返回时,这个嵌套的Ref不会触发自动脱ref。模板渲染时虽然会自动读取
.value显示内容,但typeof和JSON.stringify是直接操作Ref对象本身,所以会返回object和完整的Ref内部结构。
解决方法
方法1:使用toRefs转换返回对象
在composable中用toRefs将返回对象的属性转为独立Ref,这样组件中解构后可以利用<script setup>的自动脱ref:
// composables/useNum.js import { toRefs } from 'vue'; export const useNum = () => { const num = useState('num', () => 1); return toRefs({ num }); };
组件调用:
<script setup> const { num } = useNum(); </script> <template> <div>{{ num }}</div> <div>{{ typeof num }}</div> <pre>{{ JSON.stringify(num, null, 2) }}</pre> </template>
方法2:组件中显式访问.value(不推荐模板中使用)
如果必须保留对象返回的形式,可以在模板中直接访问Ref的.value属性:
<template> <div>{{ numStore.num.value }}</div> <div>{{ typeof numStore.num.value }}</div> <pre>{{ JSON.stringify(numStore.num.value, null, 2) }}</pre> </template>
方法3:组件中解构后手动脱ref
在<script setup>中对返回的Ref手动执行脱ref操作:
<script setup> import { unref } from 'vue'; const { num } = useNum(); const numValue = unref(num); // 等价于 num.value </script> <template> <div>{{ numValue }}</div> <div>{{ typeof numValue }}</div> <pre>{{ JSON.stringify(numValue, null, 2) }}</pre> </template>
方法4:直接返回单个Ref(适合单一值场景)
如果composable只需要返回一个状态,直接返回Ref对象,组件顶层接收后会自动脱ref:
// composables/useNum.js export const useNum = () => { return useState('num', () => 1); };
组件调用:
<script setup> const num = useNum(); </script> <template> <div>{{ num }}</div> <div>{{ typeof num }}</div> <div>{{ JSON.stringify(num) }}</div> </template>
内容的提问来源于stack exchange,提问作者Joseph
相关产品推荐
相关产品推荐

