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

如何在TanStack Vue Query中合理使用计算属性?

Vue Query 替代 Pinia/Vuex 管理服务端状态的代码组织方案

核心理解纠正

你之前的做法确实存在冗余问题——Vue Query本身就是服务端状态管理工具,它会自动缓存请求返回的数据、维护加载/错误状态,并且支持跨组件共享缓存数据,完全不需要再把服务端数据同步到Pinia中。

服务端状态(后端接口返回的列表、详情等)交给Vue Query管理,客户端状态(比如UI弹窗状态、表单输入值)才需要用Pinia或组件本地状态,这是Vue Query的核心设计思路。

代码组织方案:抽离计算逻辑到独立模块

要避免把排序、筛选这类计算逻辑写在组件本地,可以通过以下两种方式抽离:

方式1:封装成组合式函数(推荐)

把所有针对服务端数据的转换逻辑,封装成独立的组合式函数,在需要的组件中直接调用:

  1. 第一步:把请求函数抽离到API层
    不再把请求逻辑放在Pinia里,而是单独放在API模块,保持纯函数性质:

    // api/items.ts
    import axios from 'axios';
    const dbUrl = '你的接口地址';
    
    export async function fetchItems(): Promise<Item[]> {
      const response = await axios.get<Item[]>(`${dbUrl}/items`);
      return response.data || [];
    }
    
  2. 第二步:封装数据转换的组合式函数
    创建专门的组合式函数文件,存放排序、筛选等计算逻辑:

    // composables/useItemTransforms.ts
    import { computed } from 'vue';
    import type { Item } from '@/types';
    
    export function useItemTransforms(items: Ref<Item[] | undefined>) {
      // 按ID升序排序
      const sortedById = computed(() => {
        if (!items.value) return [];
        return [...items.value].sort((a, b) => a.id - b.id);
      });
    
      // 筛选已完成的项
      const completedItems = computed(() => {
        if (!items.value) return [];
        return items.value.filter(item => item.completed);
      });
    
      return { sortedById, completedItems };
    }
    
  3. 第三步:组件中使用Vue Query + 组合式函数
    组件只负责调用Vue Query获取数据,再传入组合式函数拿到处理后的结果:

    <script setup lang="ts">
    import { useQuery } from '@tanstack/vue-query';
    import { fetchItems } from '@/api/items';
    import { useItemTransforms } from '@/composables/useItemTransforms';
    
    // Vue Query获取原始数据,自带状态管理
    const { isLoading, isError, error, data: rawItems } = useQuery({
      queryKey: ['items'], // 缓存唯一标识,跨组件共享
      queryFn: fetchItems,
    });
    
    // 调用组合式函数获取处理后的数据
    const { sortedById, completedItems } = useItemTransforms(rawItems);
    </script>
    
    <template>
      <div v-if="isLoading">加载中...</div>
      <div v-else-if="isError">{{ error?.message }}</div>
      <div v-else>
        <h3>原始数据</h3>
        <div>{{ rawItems }}</div>
        <h3>按ID排序后</h3>
        <div>{{ sortedById }}</div>
        <h3>已完成项</h3>
        <div>{{ completedItems }}</div>
      </div>
    </template>
    

方式2:使用Vue Query的select选项

如果只需要对某一次查询的数据做转换,可以用Vue Query内置的select选项,把转换逻辑抽成独立函数:

// utils/itemUtils.ts
export function sortItemsById(items: Item[]) {
  return [...items].sort((a, b) => a.id - b.id);
}

// 组件中
const { data: sortedItems } = useQuery({
  queryKey: ['items'],
  queryFn: fetchItems,
  select: sortItemsById, // 直接指定转换函数
});

非官方学习资源推荐

  • 实战项目示例:找社区里的Vue3 + Vue Query实战项目(比如电商后台、任务管理系统),看别人的代码组织方式
  • 技术社区文章:掘金、知乎上的Vue Query实战总结,比如《从Pinia迁移到Vue Query的踩坑记录》这类文章
  • 视频教程:B站上的Vue Query实战教学视频,跟着做一遍小项目能快速理解核心用法
  • 社区讨论:参与Vue Query的中文社区讨论,看其他开发者遇到的类似问题和解决方案

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 07:42:41