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

Vue中嵌套Ref存储丢失响应性问题求助

Vue嵌套Ref丢失响应性:访问嵌套Ref得到值而非响应式变量

在嵌套使用Ref的场景中(原场景涉及Pinia状态管理,已简化核心代码),访问嵌套的Ref时会直接拿到对应的值,而非实际的响应式Ref对象,导致完全丢失响应性。例如调用getSourceType()会返回number,而非预期的object。

核心代码示例:

function useBar() {
  const source = ref<number>(42);
  return { source }
}

function useFoo() {
  const data = ref<Record<string, ReturnType<typeof useBar>>>({});
  data.value['test'] = useBar();

  function getSourceType() {
    return typeof data.value['test'].source;
  }

  return { getSourceType, data }
}

问题原因

Vue响应式系统在处理Ref嵌套在Reactive对象或Ref的value属性中时,会自动执行**解包(unwrap)**操作:当你把包含Ref的对象赋值给Reactive对象属性,或是Ref对象value里的对象属性时,Vue会自动将内部的Ref解包为原始值,而非保留Ref对象本身。

在你的代码里,data是一个Ref,它的value是普通对象。当你把useBar()返回的对象赋值给data.value['test']时,内部的source Ref会被自动解包,最终data.value['test'].source直接变成了原始数值42,而非Ref对象。

解决方案

根据实际业务需求,可选择以下几种方案:

1. 使用shallowRef避免自动解包

如果不需要data内部的对象具备深度响应性,用shallowRef创建data,Vue不会对data.value里的属性进行自动解包:

import { shallowRef, ref } from 'vue';

function useBar() {
  const source = ref<number>(42);
  return { source }
}

function useFoo() {
  const data = shallowRef<Record<string, ReturnType<typeof useBar>>>({});
  data.value['test'] = useBar();

  function getSourceType() {
    return typeof data.value['test'].source; // 现在返回'object'
  }

  return { getSourceType, data }
}

2. 使用markRaw标记非响应式对象

用markRaw标记useBar()返回的对象,让Vue不对其进行响应式转换,从而保留内部的Ref对象:

import { markRaw, ref } from 'vue';

function useBar() {
  const source = ref<number>(42);
  return { source }
}

function useFoo() {
  const data = ref<Record<string, ReturnType<typeof useBar>>>({});
  data.value['test'] = markRaw(useBar()); // 标记为非响应式

  function getSourceType() {
    return typeof data.value['test'].source; // 返回'object'
  }

  return { getSourceType, data }
}

3. 双重Ref包裹(保留深度响应性)

如果需要data本身保持深度响应性,同时保留内部的Ref对象,可以给返回的Ref再套一层Ref:

import { ref } from 'vue';

function useBar() {
  const source = ref<number>(42);
  return { source: ref(source) }; // 双重Ref包裹
}

function useFoo() {
  const data = ref<Record<string, ReturnType<typeof useBar>>>({});
  data.value['test'] = useBar();

  function getSourceType() {
    return typeof data.value['test'].source.value; // 需多访问一层value
  }

  return { getSourceType, data }
}

这种方式下,外层Ref会被自动解包,但内部的Ref会被保留,访问原始值时需要多调用一次.value。

内容的提问来源于stack exchange,提问作者KorbenDose

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 03:51:16