MD 状态:🌿 分类:系统与架构 更新:2026/5/29

GraphQL vs TanStack Query

[!abstract] 一句话总结 GraphQL 是 API 的设计语言,TanStack Query 是前端的数据管家。它们不是竞争关系,而是可以互补的技术栈。

本质区别

维度GraphQLTanStack Query
类型API 查询语言规范前端数据获取和状态管理库
解决什么问题如何定义和查询 API如何管理异步数据状态
运行位置服务端 + 客户端仅客户端
数据源定义 API 本身可连接任何 API(REST、GraphQL、WebSocket)
学习成本较高(Schema、类型系统、解析器)中等(查询、缓存、失效策略)
典型生态Apollo Server/Client、Relay、urqlReact、Vue、Svelte、Angular、Solid

核心类比

把它们想象成餐厅系统:

  • GraphQL = 餐厅的菜单系统(定义你可以点什么、菜品的组合方式)
  • TanStack Query = 你的管家(帮你点餐、记住你点过什么、自动续杯、处理异常)

两者配合:管家(TanStack Query)拿着菜单(GraphQL)帮你高效点餐。

架构关系图

graph TB
    subgraph 前端应用
        A[TanStack Query<br/>状态管理层] --> B[GraphQL 客户端<br/>Apollo/urql]
        A --> C[REST/fetch]
    end
    
    B --> D[GraphQL API]
    C --> E[REST API]
    
    style A fill:#e1f5fe
    style B fill:#f3e5f5
    style C fill:#f3e5f5

层次说明

  • TanStack Query 处于状态管理层,负责缓存、重试、后台刷新、乐观更新
  • GraphQL 客户端处于数据获取层,负责发送查询和解析响应
  • 两者可以独立使用,也可以组合使用

使用方式对比

方式一:只用 GraphQL (Apollo Client)

import { useQuery, gql } from '@apollo/client';

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) { id name email }
  }
`;

function User({ id }) {
  const { loading, error, data } = useQuery(GET_USER, { 
    variables: { id } 
  });
  // Apollo Client 自带缓存和状态管理
}

特点:一站式解决方案,缓存逻辑内置,但与 Apollo 生态绑定较深。

方式二:只用 TanStack Query (REST)

import { useQuery } from '@tanstack/react-query';

function User({ id }) {
  const { isLoading, error, data } = useQuery({
    queryKey: ['user', id],
    queryFn: () => fetch(`/api/users/${id}`).then(r => r.json()),
  });
  // TanStack Query 管理缓存和状态
}

特点:框架无关,灵活可控,但需要自己处理数据获取细节。

方式三:两者结合使用

import { useQuery } from '@tanstack/react-query';
import { request, gql } from 'graphql-request';

const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) { id name email }
  }
`;

function User({ id }) {
  const { isLoading, error, data } = useQuery({
    queryKey: ['user', id],
    queryFn: () => request('/graphql', GET_USER, { id }),
  });
  // TanStack Query 管理状态,GraphQL 定义查询
}

特点:最佳实践之一,结合 GraphQL 的查询能力和 TanStack Query 的状态管理能力。

功能特性对比

特性Apollo ClientTanStack Query
缓存✅ 归一化缓存(自动)✅ 查询键缓存(手动配置)
后台刷新✅ 轮询✅ 自动后台刷新
乐观更新✅ 支持✅ 支持
重试机制✅ 基础✅ 高级(指数退避)
离线支持✅ 有✅ 有
DevTools✅ Apollo DevTools✅ TanStack Query DevTools
框架支持React、Vue、AngularReact、Vue、Svelte、Angular、Solid
学习曲线较陡中等

选择决策树

graph TD
    A[开始选择] --> B{API 类型?}
    B -->|GraphQL| C{需要深度缓存?}
    B -->|REST| D[TanStack Query]
    
    C -->|是| E[Apollo Client / Relay]
    C -->|否| F[TanStack Query + graphql-request]
    
    E --> G{需要跨框架?}
    F --> G
    
    G -->|是| H[TanStack Query]
    G -->|否| I[根据团队熟悉度选择]
    
    style D fill:#c8e6c9
    style E fill:#c8e6c9
    style F fill:#c8e6c9
    style H fill:#c8e6c9

选择建议

场景推荐方案理由
项目已用 GraphQL,需要强大缓存Apollo Client 或 Relay一站式解决方案,归一化缓存强大
项目用 REST,想优化数据获取TanStack Query简单易用,自动处理 loading/error 状态
项目用 GraphQL,想更灵活的缓存控制TanStack Query + graphql-request解耦缓存逻辑,便于跨框架
新项目,团队熟悉 React 生态TanStack Query + REST 或 GraphQL学习成本低,社区活跃
需要跨框架(Vue/Svelte/Angular)TanStack Query框架无关,统一 API
移动端 React NativeApollo Client 或 TanStack Query两者都支持良好

各自的优势

GraphQL 的优势

  • ✅ 精确获取数据,避免过度获取/不足获取
  • ✅ 强类型 Schema,API 自文档化
  • ✅ 一次请求获取关联数据
  • ✅ 版本演进无需破坏性变更

TanStack Query 的优势

  • ✅ 框架无关,一套 API 多端复用
  • ✅ 自动后台刷新和缓存失效
  • ✅ 简洁的 API,学习成本低
  • ✅ 强大的 DevTools 支持
  • ✅ 乐观更新和离线支持

常见误解

[!danger] ❌ 误以为:GraphQL 和 TanStack Query 是竞争关系 ✅ 实际上:它们是不同层次的技术,可以互补使用。GraphQL 定义 API,TanStack Query 管理状态。

[!danger] ❌ 误以为:用了 GraphQL 就必须用 Apollo Client ✅ 实际上:你可以用 TanStack Query + graphql-request,或者 urql 等其他客户端。

[!danger] ❌ 误以为:TanStack Query 只能用于 REST ✅ 实际上:TanStack Query 可以连接任何异步数据源,包括 GraphQL、WebSocket、甚至本地函数。

实战组合推荐

组合一:全栈 GraphQL 方案

前端:Apollo Client / Relay
后端:Apollo Server / GraphQL Yoga
适用:大型项目,需要深度缓存和实时更新

组合二:灵活混合方案

前端:TanStack Query + graphql-request
后端:Apollo Server / GraphQL Yoga
适用:需要跨框架支持,或想要更灵活的缓存控制

组合三:REST 优化方案

前端:TanStack Query
后端:REST API + OpenAPI 规范
适用:传统 REST API,想优化数据获取体验

关联笔记

前置知识GraphQL · REST API · React 同族概念Apollo Client · Relay · urql · SWR 应用场景前后端分离 · 单页应用 · 移动应用开发