在React中使用Apollo Client存储GraphQL查询的最佳实践
GraphQL查询存储最佳实践(结合Apollo使用)
一、硬编码查询的存储方案
别把查询散在各个组件里,统一放到单独的目录管理更省心。比如在项目里建个src/graphql/queries/文件夹,按业务模块分组存放查询,比如用户相关的放PersonQueries.js,订单相关的放OrderQueries.js。
示例:查询文件
// src/graphql/queries/PersonQueries.js import { gql } from '@apollo/client'; // 获取单个用户 export const FETCH_PERSON = gql` query FetchPerson($id: ID!) { person(id: $id) { id name age } } `; // 获取所有用户 export const FETCH_ALL_PERSONS = gql` query FetchAllPersons { persons { id name } } `;
组件中使用
import { FETCH_PERSON } from '../graphql/queries/PersonQueries'; import { useQuery } from '@apollo/client'; function PersonDetail({ personId }) { const { data, loading, error } = useQuery(FETCH_PERSON, { variables: { id: personId } // 直接传参数给Apollo的useQuery }); // 渲染逻辑 }
二、带参数的查询处理
不需要搞什么辅助类,Apollo本身就支持通过variables传参。如果遇到需要动态调整查询内容(比如按需返回字段、动态过滤条件),写简单的工具函数就行,比类灵活多了。
示例1:动态控制返回字段
比如根据需求决定是否返回用户年龄:
// src/graphql/utils/queryUtils.js import { gql } from '@apollo/client'; export const getFetchPersonQuery = (includeAge = true) => { const fields = includeAge ? 'id name age' : 'id name'; return gql` query FetchPerson($id: ID!) { person(id: $id) { ${fields} } } `; };
组件里用的时候:
import { getFetchPersonQuery } from '../graphql/utils/queryUtils'; import { useQuery } from '@apollo/client'; function PersonCard({ personId, showAge }) { const fetchPersonQuery = getFetchPersonQuery(showAge); const { data } = useQuery(fetchPersonQuery, { variables: { id: personId } }); return ( <div> {data?.person.name} {showAge && ` (${data?.person.age}岁)`} </div> ); }
示例2:动态生成过滤条件
比如多条件筛选用户(按姓名模糊搜索、年龄大于某个值):
// src/graphql/utils/queryUtils.js export const getFilteredPersonsQuery = (filters) => { let variableDefs = '$name: String, $minAge: Int'; let whereClause = ''; const conditions = []; // 根据传入的filters构建查询条件 if (filters.name) conditions.push(`name_contains: $name`); if (filters.minAge) conditions.push(`age_gt: $minAge`); if (conditions.length) { whereClause = `where: { ${conditions.join(', ')} }`; } return gql` query FilteredPersons(${variableDefs}) { persons(${whereClause}) { id name age } } `; };
组件使用:
import { getFilteredPersonsQuery } from '../graphql/utils/queryUtils'; import { useQuery } from '@apollo/client'; function PersonList({ filters }) { const filteredQuery = getFilteredPersonsQuery(filters); const { data } = useQuery(filteredQuery, { variables: { name: filters.name, minAge: filters.minAge } }); return ( <ul> {data?.persons.map(person => ( <li key={person.id}>{person.name}</li> ))} </ul> ); }
三、进阶方案:用代码生成工具(GraphQL Codegen)
如果是大型项目,手动维护查询和变量容易出错,可以用GraphQL Codegen自动生成类型安全的查询hooks,省不少事。
大致步骤
- 安装依赖:
npm install @graphql-codegen/cli @graphql-codegen/client-preset --save-dev
- 配置
codegen.ts:
import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { schema: './src/graphql/schema.graphql', // 你的GraphQL schema文件或远程端点地址 documents: ['./src/graphql/queries/**/*.graphql'], // 存放.graphql查询文件的目录 generates: { './src/graphql/generated/': { preset: 'client', plugins: [] } } }; export default config;
- 写单独的
.graphql查询文件:
# src/graphql/queries/fetchPerson.graphql query FetchPerson($id: ID!) { person(id: $id) { id name age } }
- 运行生成命令:
npx graphql-codegen
- 组件里直接用生成的hooks:
import { useFetchPersonQuery } from '../graphql/generated'; function PersonDetail({ personId }) { const { data, loading } = useFetchPersonQuery({ variables: { id: personId } }); // 直接用类型安全的data }
四、避坑提醒
- 别用辅助类存查询:类会增加不必要的复杂度,函数式工具或者单独的查询文件更清爽。
- 别在组件里堆大量查询:分散的查询难维护,统一管理才是正道。
内容的提问来源于stack exchange,提问作者user3344447
相关产品推荐
相关产品推荐

