如何在Apollo Client中复用一个查询结果作为另一个查询的参数?
实现方案
1. 客户端逐个触发评论查询
先通过useQuery获取案件列表,再针对每个案件ID,用带skip条件的useQuery触发评论查询。这种方式无需后端改动,适合数据量不大的场景。
代码示例
import { useQuery, gql } from '@apollo/client'; // 案件列表查询 const GET_CASES = gql` query GetCases { cases { id title // 其他案件字段 } } `; // 单案件评论查询 const GET_CASE_COMMENTS = gql` query GetCaseComments($caseId: ID!) { caseComments(caseId: $caseId) { id content author } } `; export default function CasesPage() { const { loading: casesLoading, data: casesData } = useQuery(GET_CASES); if (casesLoading) return <div>加载案件中...</div>; if (!casesData?.cases) return <div>无案件数据</div>; return ( <div> {casesData.cases.map((caseItem) => ( <div key={caseItem.id}> <h3>{caseItem.title}</h3> <CaseComments caseId={caseItem.id} /> </div> ))} </div> ); } function CaseComments({ caseId }) { const { loading: commentsLoading, data: commentsData } = useQuery(GET_CASE_COMMENTS, { variables: { caseId }, skip: !caseId, // 确保caseId存在才触发查询 }); if (commentsLoading) return <div>加载评论中...</div>; return ( <ul> {commentsData?.caseComments.map(comment => ( <li key={comment.id}>{comment.content} - {comment.author}</li> ))} </ul> ); }
2. 批量请求评论(需后端支持批量ID查询)
如果后端允许通过ID数组批量查询评论(比如提供接受caseIds: [ID!]参数的查询),可以先收集所有案件ID,一次性请求所有评论,再在前端匹配到对应案件,能减少请求次数、提升性能。
代码示例
import { useQuery, gql } from '@apollo/client'; const GET_CASES = gql` query GetCases { cases { id title } } `; // 批量评论查询(假设后端支持) const GET_BATCH_COMMENTS = gql` query GetBatchComments($caseIds: [ID!]!) { batchCaseComments(caseIds: $caseIds) { caseId comments { id content author } } } `; export default function CasesPage() { const { loading: casesLoading, data: casesData } = useQuery(GET_CASES); const caseIds = casesData?.cases?.map(c => c.id) || []; const { loading: commentsLoading, data: commentsData } = useQuery(GET_BATCH_COMMENTS, { variables: { caseIds }, skip: caseIds.length === 0, }); if (casesLoading || commentsLoading) return <div>加载中...</div>; if (!casesData?.cases) return <div>无案件数据</div>; // 按caseId整理评论,方便匹配 const commentsMap = {}; commentsData?.batchCaseComments.forEach(item => { commentsMap[item.caseId] = item.comments; }); return ( <div> {casesData.cases.map((caseItem) => ( <div key={caseItem.id}> <h3>{caseItem.title}</h3> <ul> {(commentsMap[caseItem.id] || []).map(comment => ( <li key={comment.id}>{comment.content} - {comment.author}</li> ))} </ul> </div> ))} </div> ); }
3. 利用Apollo缓存手动关联数据
通过Apollo Client的writeFragment,将查询到的评论数据写入对应案件的缓存条目,之后可以直接从案件缓存中读取关联的评论,实现类似Schema关联的效果。
代码示例
import { useQuery, gql, useApolloClient } from '@apollo/client'; const GET_CASES = gql` query GetCases { cases { id title } } `; const GET_ALL_COMMENTS = gql` query GetAllComments { allCaseComments { id content author caseId } } `; // 定义案件Fragment,用于缓存写入 const CASE_FRAGMENT = gql` fragment CaseWithComments on Case { id comments { id content author } } `; export default function CasesPage() { const client = useApolloClient(); const { loading: casesLoading, data: casesData } = useQuery(GET_CASES); const { loading: commentsLoading, data: commentsData } = useQuery(GET_ALL_COMMENTS); // 数据加载完成后,关联评论到案件缓存 if (!casesLoading && !commentsLoading && casesData?.cases && commentsData?.allCaseComments) { const commentsByCaseId = {}; commentsData.allCaseComments.forEach(comment => { commentsByCaseId[comment.caseId] = [...(commentsByCaseId[comment.caseId] || []), comment]; }); casesData.cases.forEach(caseItem => { client.writeFragment({ id: client.cache.identify(caseItem), // 生成案件缓存ID fragment: CASE_FRAGMENT, data: { ...caseItem, comments: commentsByCaseId[caseItem.id] || [], }, }); }); } if (casesLoading || commentsLoading) return <div>加载中...</div>; if (!casesData?.cases) return <div>无案件数据</div>; return ( <div> {casesData.cases.map((caseItem) => { // 从缓存读取带评论的案件数据 const caseWithComments = client.readFragment({ id: client.cache.identify(caseItem), fragment: CASE_FRAGMENT, }); return ( <div key={caseItem.id}> <h3>{caseWithComments.title}</h3> <ul> {(caseWithComments.comments || []).map(comment => ( <li key={comment.id}>{comment.content} - {comment.author}</li> ))} </ul> </div> ); })} </div> ); }
4. NextJS服务端预取数据
在NextJS的getServerSideProps或getStaticProps中,先获取案件列表,再批量获取所有评论,组装好数据后传给前端组件,前端无需额外请求,适合SEO友好的场景。
代码示例(getServerSideProps)
import { gql } from '@apollo/client'; import { initializeApollo } from '../lib/apollo'; // 假设你有初始化Apollo客户端的工具函数 const GET_CASES = gql` query GetCases { cases { id title } } `; const GET_ALL_COMMENTS = gql` query GetAllComments { allCaseComments { id content author caseId } } `; export default function CasesPage({ casesWithComments }) { return ( <div> {casesWithComments.map((caseItem) => ( <div key={caseItem.id}> <h3>{caseItem.title}</h3> <ul> {(caseItem.comments || []).map(comment => ( <li key={comment.id}>{comment.content} - {comment.author}</li> ))} </ul> </div> ))} </div> ); } export async function getServerSideProps() { const apolloClient = initializeApollo(); // 获取案件列表 const casesResult = await apolloClient.query({ query: GET_CASES }); const cases = casesResult.data.cases || []; // 获取所有评论 const commentsResult = await apolloClient.query({ query: GET_ALL_COMMENTS }); const allComments = commentsResult.data.allCaseComments || []; // 组装案件与评论 const commentsByCaseId = {}; allComments.forEach(comment => { commentsByCaseId[comment.caseId] = [...(commentsByCaseId[comment.caseId] || []), comment]; }); const casesWithComments = cases.map(caseItem => ({ ...caseItem, comments: commentsByCaseId[caseItem.id] || [], })); return { props: { casesWithComments, }, }; }
内容的提问来源于stack exchange,提问作者Browny
相关产品推荐
相关产品推荐

