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

更新Ref未触发组合式函数重计算问题排查

问题:更新Ref后usePostData未触发数据获取,无法获取最新帖子

我尝试更新一个ref对象,期望触发数据获取逻辑返回更新后的数据,但该逻辑未生效。Ref值已更新,但usePostData并未触发,无法获取最新帖子。相关代码如下:

App.vue

<script setup lang="ts">
import { ref } from 'vue';
import {usePostData} from './api/usePost.js';

const postToFetch = ref({
  id: 1
})

const onClick = () => {
  postToFetch.value.id++;
}

const { data, isError, isLoading} = usePostData(postToFetch);

</script>

<template>
  <div v-if="isError">Error Fetching Data</div>
  <div v-if="isLoading">Loading</div>
  <div v-if="data">
    <div style="border: 1px dotted green; padding: 10px">
      <pre style="color: red; padding: 2px;">Ref  = {{ postToFetch.id }}</pre>
      <h2>Post Id: {{ data.id }} </h2>
      <h3>Title: {{ data.title }}</h3>
      <p>Content: {{ data.body}}</p>
    </div>
  </div>
  <button @click="onClick">Fetch Next Post</button>
</template>

usePost.js

import { useQuery } from '@tanstack/vue-query'

async function fetchPost(postId) {
    return await fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`).then(response => response.json())
}

export function usePostData(postToFetch) { 
  return useQuery({
    queryKey: ['post', postToFetch.value.id],
    queryFn: () => fetchPost(postToFetch.value.id),
    refetchOnWindowFocus: false
  })
}

错误原因

  • TanStack Vue Query的useQuery不会自动监听ref对象内部属性的变化。当前代码中queryKey仅在组件初始化时读取一次postToFetch.value.id,后续id更新时,queryKey不会同步变化,因此useQuery不会触发重新请求。
  • 传入的postToFetch是包含对象的ref,即使ref本身是响应式的,但useQuery无法感知内部id属性的更新,因为没有将queryKey设置为响应式依赖。

解决方案

方法一:改用单个ref(推荐)

由于仅需跟踪id的变化,无需用对象包裹,直接使用单个ref更简洁:

修改App.vue

<script setup lang="ts">
import { ref } from 'vue';
import {usePostData} from './api/usePost.js';

// 将对象ref改为单个id的ref
const postToFetchId = ref(1)

const onClick = () => {
  postToFetchId.value++;
}

const { data, isError, isLoading} = usePostData(postToFetchId);

</script>

<template>
  <div v-if="isError">Error Fetching Data</div>
  <div v-if="isLoading">Loading</div>
  <div v-if="data">
    <div style="border: 1px dotted green; padding: 10px">
      <pre style="color: red; padding: 2px;">Ref  = {{ postToFetchId }}</pre>
      <h2>Post Id: {{ data.id }} </h2>
      <h3>Title: {{ data.title }}</h3>
      <p>Content: {{ data.body}}</p>
    </div>
  </div>
  <button @click="onClick">Fetch Next Post</button>
</template>

修改usePost.js

import { useQuery } from '@tanstack/vue-query'
import { computed } from 'vue'

async function fetchPost(postId) {
    return await fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`).then(response => response.json())
}

export function usePostData(postIdRef) { 
  // 用computed包装queryKey,使其成为响应式依赖
  const queryKey = computed(() => ['post', postIdRef.value])
  
  return useQuery({
    queryKey: queryKey,
    queryFn: () => fetchPost(postIdRef.value),
    refetchOnWindowFocus: false
  })
}

方法二:保留对象ref,用computed监听内部属性

如果必须保留对象形式的ref,需要在usePostData中通过computed监听id的变化:

修改usePost.js

import { useQuery } from '@tanstack/vue-query'
import { computed } from 'vue'

async function fetchPost(postId) {
    return await fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`).then(response => response.json())
}

export function usePostData(postToFetch) { 
  // 用computed监听postToFetch.value.id的变化,同步更新queryKey
  const queryKey = computed(() => ['post', postToFetch.value.id])
  
  return useQuery({
    queryKey: queryKey,
    queryFn: () => fetchPost(postToFetch.value.id),
    refetchOnWindowFocus: false
  })
}

当postToFetch.value.id更新时,computed返回的queryKey会同步变化,触发useQuery重新执行请求,获取最新帖子数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 10:17:47