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

Vue 3 组合式函数Ref行为异常:异步请求数据无法正常访问

问题分析:Vue组合式函数useAxiosGet中data.value返回null的原因

问题重现

你封装的useAxiosGet组合式函数代码:

// inside useAxiosGet.js
import { ref, watchEffect } from 'vue';
import axios from 'axios';
export default function (url) {
  const data = ref(null);

  watchEffect(async () => {
    axios({
      url: url
    })
      .then((res) => {
        data.value = res.data;
      })
      .catch((err) => console.log(err));
  });

  return { data };
}

使用时的代码及现象:

<script setup>
const { data } = useAxiosGet('my/path/to/backend/');
console.log(data); // 输出Ref包装对象,可在_rawValue中找到数据
console.log(isRef(data)) // 输出true,解构后未失去响应性
console.log(data.value); // 输出'null'
</script>

核心原因

1. 异步请求的时序问题

axios的GET请求是异步操作,不会阻塞后续代码执行。当你执行console.log(data.value)时,后端请求还在处理中,还未返回数据,此时data的初始值null还没被更新。

2. 控制台的“实时更新”误导

你在控制台的Ref对象里看到_rawValue有数据,是因为当你展开查看这个对象时,异步请求已经完成,data.value已经被回调函数更新了——控制台会实时展示对象的最新状态,而不是执行console.log那一刻的快照。

3. watchEffect的执行逻辑

watchEffect会在组件初始化时立即触发,但里面的axios请求是异步的,then回调要等请求完成后才会执行,这时候你同步编写的console.log早就执行完毕了。

验证与解决方法

方法1:监听数据变化

用watch监听data的更新,请求完成后就能拿到数据:

<script setup>
import { watch } from 'vue';
const { data } = useAxiosGet('my/path/to/backend/');

watch(data, (newData) => {
  console.log(newData); // 请求完成后会打印后端返回的数据
});
</script>

方法2:在模板中直接使用

Vue模板会自动解包Ref,并且会响应式更新,可直接在模板中使用(推荐搭配可选链操作符避免报错):

<template>
  <div>{{ data?.username }}</div>
</template>

方法3:优化组合式函数(推荐)

给函数添加加载状态、错误处理,还能避免组件卸载时的请求泄漏:

// 优化后的useAxiosGet.js
import { ref, watchEffect } from 'vue';
import axios from 'axios';
export default function (url) {
  const data = ref(null);
  const loading = ref(true);
  const error = ref(null);

  watchEffect((onCleanup) => {
    const cancelToken = axios.CancelToken.source();
    loading.value = true;
    error.value = null;

    axios({
      url,
      cancelToken: cancelToken.token
    })
      .then(res => data.value = res.data)
      .catch(err => {
        if (!axios.isCancel(err)) {
          error.value = err;
          console.error('请求失败:', err);
        }
      })
      .finally(() => loading.value = false);

    // 组件卸载或依赖变化时取消请求
    onCleanup(() => cancelToken.cancel('请求已取消'));
  });

  return { data, loading, error };
}

使用优化后的函数:

<script setup>
const { data, loading, error } = useAxiosGet('my/path/to/backend/');

// 可以根据loading状态处理加载提示
if (loading.value) console.log('请求中...');
if (error.value) console.log('请求出错:', error.value);
</script>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 08:02:35