# 查询模式 本参考文档涵盖了编写高效 GraphQL 查询的模式。 ## 目录 - [查询结构](#查询结构) - [字段选择](#字段选择) - [别名](#别名) - [指令](#指令) - [查询命名](#查询命名) - [查询组织](#查询组织) - [性能优化](#性能优化) ## 查询结构 ### 基本查询 ```graphql query GetUser($id: ID!) { user(id: $id) { id name email } } ``` 组成部分: - `query` — 操作类型 - `GetUser` — 操作名称 - `($id: ID!)` — 变量定义 - `user(id: $id)` — 带参数的字段 - `{ id name email }` — 选择集 ### 多根字段查询 ```graphql query GetDashboardData($userId: ID!) { user(id: $userId) { id name } notifications(first: 5) { id message } stats { totalPosts totalComments } } ``` ### 嵌套查询 ```graphql query GetUserWithPosts($userId: ID!) { user(id: $userId) { id name posts(first: 10) { edges { node { id title comments(first: 3) { edges { node { id body } } } } } } } } ``` ## 字段选择 ### 只请求需要的字段 ```graphql # 用户卡片组件 query GetUserCard($id: ID!) { user(id: $id) { id name avatarUrl # 如果不展示,不要请求 email、bio 等字段 } } ``` ### 始终包含 ID 字段 为可能缓存或重新获取的类型包含 `id`: ```graphql query GetPost($id: ID!) { post(id: $id) { id # 始终包含,用于缓存 title author { id # 包含,用于作者缓存条目 name } } } ``` ### 选择连接(Connection) 对于分页数据,按需请求: ```graphql query GetUserPosts($userId: ID!, $first: Int!, $after: String) { user(id: $userId) { id posts(first: $first, after: $after) { edges { node { id title excerpt } cursor # 仅在实现无限滚动时需要 } pageInfo { hasNextPage endCursor } totalCount # 仅在展示总数时需要 } } } ``` ## 别名 ### 基本别名 在响应中重命名字段: ```graphql query GetUserNames($id: ID!) { user(id: $id) { userId: id displayName: name } } # 响应:{ user: { userId: "123", displayName: "John" } } ``` ### 多次查询同一字段 ```graphql query GetMultipleUsers { admin: user(id: "1") { id name } moderator: user(id: "2") { id name } currentUser: user(id: "3") { id name } } ``` ### 使用不同参数的别名 ```graphql query GetPostsByStatus($userId: ID!) { user(id: $userId) { id publishedPosts: posts(status: PUBLISHED, first: 5) { edges { node { id title } } } draftPosts: posts(status: DRAFT, first: 5) { edges { node { id title } } } } } ``` ## 指令 ### @include 指令 仅当条件为 true 时包含字段: ```graphql query GetUser($id: ID!, $includeEmail: Boolean!) { user(id: $id) { id name email @include(if: $includeEmail) } } # 变量:{ id: "123", includeEmail: true } # 返回 email 字段 # 变量:{ id: "123", includeEmail: false } # 不返回 email 字段 ``` ### @skip 指令 当条件为 true 时跳过字段: ```graphql query GetPost($id: ID!, $isPreview: Boolean!) { post(id: $id) { id title content @skip(if: $isPreview) excerpt } } ``` ### 在片段上使用指令 ```graphql query GetUser($id: ID!, $expanded: Boolean!) { user(id: $id) { id name ...UserDetails @include(if: $expanded) } } fragment UserDetails on User { bio website socialLinks { platform url } } ``` ### 组合使用指令 ```graphql query GetPost($id: ID!, $showComments: Boolean!, $hideAuthor: Boolean!) { post(id: $id) { id title author @skip(if: $hideAuthor) { id name } comments(first: 10) @include(if: $showComments) { edges { node { id body } } } } } ``` ## 查询命名 ### 命名约定 | 用途 | 模式 | 示例 | | --------------- | --------------- | ----------------------------------- | | 获取单个条目 | `Get{Type}` | `GetUser`,`GetPost` | | 获取列表 | `List{Types}` | `ListUsers`,`ListPosts` | | 搜索 | `Search{Types}` | `SearchUsers`,`SearchProducts` | | 为特定 UI 获取 | `Get{Feature}Data` | `GetDashboardData`,`GetProfilePage` | ### 好的命名 ```graphql query GetUserProfile($id: ID!) { ... } query ListRecentPosts($first: Int!) { ... } query SearchProducts($query: String!) { ... } query GetOrderDetails($orderId: ID!) { ... } query GetHomeFeed($userId: ID!) { ... } ``` ### 避免泛化命名 ```graphql # 避免 query Data { ... } query Query1 { ... } query FetchStuff { ... } # 推荐 query GetCurrentUser { ... } query ListActiveProjects { ... } query SearchCustomers($query: String!) { ... } ``` ## 查询组织 ### 每个文件一个查询 ``` src/ graphql/ queries/ GetUser.graphql ListPosts.graphql SearchProducts.graphql ``` ```graphql # GetUser.graphql query GetUser($id: ID!) { user(id: $id) { id name email } } ``` ### 与组件同目录放置 ``` src/ components/ UserProfile/ UserProfile.tsx UserProfile.graphql UserProfile.test.tsx ``` ### 导入并使用 ```typescript // 使用 graphql-tag import { gql } from "@apollo/client"; export const GET_USER = gql` query GetUser($id: ID!) { user(id: $id) { id name } } `; // 使用 .graphql 文件(需要加载器) import { GetUserDocument } from "./UserProfile.generated"; ``` ## 性能优化 ### 避免过度获取 只请求组件会用到的字段: ```graphql # 列表视图——最少字段 query ListPostsForIndex { posts(first: 20) { edges { node { id title excerpt author { name } } } } } # 详情视图——更多字段 query GetPostDetail($id: ID!) { post(id: $id) { id title content publishedAt author { id name bio avatarUrl } comments(first: 10) { ... } } } ``` ### 使用分页 切勿获取无界列表: ```graphql # 避免 query GetAllPosts { posts { # 可能返回数千条 id title } } # 推荐 query GetPosts($first: Int = 20, $after: String) { posts(first: $first, after: $after) { edges { node { id title } } pageInfo { hasNextPage endCursor } } } ``` ### 批量合并相关查询 在一次请求中获取相关数据: ```graphql # 替代多次查询 query GetDashboard($userId: ID!) { user(id: $userId) { id name } recentPosts: posts(first: 5, orderBy: { field: CREATED_AT, direction: DESC }) { edges { node { id title } } } notifications(first: 10, unreadOnly: true) { edges { node { id message } } } } ``` ### 对重复选择集使用片段 ```graphql query GetPostsWithAuthors { posts(first: 10) { edges { node { id title author { ...AuthorInfo } } } } featuredPost { id title author { ...AuthorInfo } } } fragment AuthorInfo on User { id name avatarUrl } ```