更新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
相关产品推荐
相关产品推荐

