You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 00:45:19