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

如何在React D3 Tree中用Apollo实现全量ID循环依赖查询?

解决方案:获取全量层级依赖数据

核心思路

由于各层级存在链式依赖(enterprise → factory → area → node),要获取全量数据,必须遍历上层所有数据,为每个父节点发起对应的下层查询,最后将结果关联到父节点的子节点集合中。

实现代码

使用useLazyQuery配合异步遍历实现全量查询

useQuery适用于单次固定参数查询,批量嵌套查询更适合用useLazyQuery手动触发,结合useEffect监听上层数据完成后发起批量请求:

import { useQuery, useLazyQuery } from '@apollo/client';
import { useEffect, useState } from 'react';
import Tree from 'react-d3-tree';

// 导入你的GraphQL查询
import GET_ENTERPRISES from './queries/GetEnterprises';
import GET_FACTORIES from './queries/GetFactories';
import GET_AREAS from './queries/GetAreas';
import GET_NODES from './queries/GetNodes';

const FullTreeComponent = () => {
  // 获取所有顶层企业
  const { data: enterprisesData, loading: loadingEnterprises } = useQuery(GET_ENTERPRISES);
  // 存储最终的全量树形数据
  const [fullTreeData, setFullTreeData] = useState([]);

  // 初始化懒加载查询函数
  const [fetchFactories] = useLazyQuery(GET_FACTORIES);
  const [fetchAreas] = useLazyQuery(GET_AREAS);
  const [fetchNodes] = useLazyQuery(GET_NODES);

  useEffect(() => {
    // 上层企业数据未加载完成时直接返回
    if (!enterprisesData?.enterprises) return;

    // 异步遍历获取全量层级数据
    const buildFullTree = async () => {
      const enterpriseTree = await Promise.all(
        enterprisesData.enterprises.map(async (enterprise) => {
          // 获取当前企业下的所有工厂
          const factoryResult = await fetchFactories({
            variables: { enterprise_id: enterprise.id }
          }).catch(err => {
            console.error(`加载企业${enterprise.id}的工厂失败:`, err);
            return { data: { factories: [] } };
          });

          const factories = factoryResult.data?.factories || [];
          const factoryTree = await Promise.all(
            factories.map(async (factory) => {
              // 获取当前工厂下的所有区域
              const areaResult = await fetchAreas({
                variables: { factory_id: factory.id }
              }).catch(err => {
                console.error(`加载工厂${factory.id}的区域失败:`, err);
                return { data: { areas: [] } };
              });

              const areas = areaResult.data?.areas || [];
              const areaTree = await Promise.all(
                areas.map(async (area) => {
                  // 获取当前区域下的所有节点
                  const nodeResult = await fetchNodes({
                    variables: { area_id: area.id }
                  }).catch(err => {
                    console.error(`加载区域${area.id}的节点失败:`, err);
                    return { data: { nodes: [] } };
                  });

                  // 组装区域节点数据,子节点为对应nodes
                  return {
                    ...area,
                    children: nodeResult.data?.nodes || []
                  };
                })
              );

              // 组装工厂数据,子节点为对应areas
              return {
                ...factory,
                children: areaTree
              };
            })
          );

          // 组装企业数据,子节点为对应factories
          return {
            ...enterprise,
            children: factoryTree
          };
        })
      );

      setFullTreeData(enterpriseTree);
    };

    buildFullTree();
  }, [enterprisesData, fetchFactories, fetchAreas, fetchNodes]);

  if (loadingEnterprises) {
    return <div>加载中...</div>;
  }

  // 将全量树形数据传入react-d3-tree组件
  return <Tree data={fullTreeData} />;
};

export default FullTreeComponent;

可选优化:利用Apollo缓存减少重复请求

如果数据不会频繁变更,可以给懒加载查询添加fetchPolicy: 'cache-first',优先使用缓存数据避免重复请求:

const [fetchFactories] = useLazyQuery(GET_FACTORIES, { fetchPolicy: 'cache-first' });
const [fetchAreas] = useLazyQuery(GET_AREAS, { fetchPolicy: 'cache-first' });
const [fetchNodes] = useLazyQuery(GET_NODES, { fetchPolicy: 'cache-first' });

原方案问题分析

原代码中直接使用enterprises?.enterprises[0].id作为参数,仅为第一个企业发起工厂查询,后续的区域、节点查询也仅基于第一个工厂、第一个区域,因此只能拿到单条链路的数据,无法获取全量层级信息。

内容的提问来源于stack exchange,提问作者Misil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 04:45:40