如何在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
相关产品推荐
相关产品推荐

