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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 09:22:49