react-admin中如何获取getList返回的aggs聚合数据?
解决React-Admin中从getList获取ElasticSearch聚合数据(aggs)的方案
方案1:自定义Hook封装useListContext,提取聚合数据
React-Admin的useListContext只暴露了data和total,但getList的完整响应包含aggs。我们可以封装一个自定义Hook,结合useListContext和useQuery获取完整响应,再把聚合数据注入到上下文结果中:
import { useListContext, useQuery } from 'react-admin'; import { dataProvider } from './path-to-your-data-provider'; export const useListWithAggs = () => { const listContext = useListContext(); const { resource, pagination, sort, filter } = listContext; // 获取getList的完整响应,包含aggs const { data: rawResponse } = useQuery( // 用请求参数作为Query Key,确保参数变化时自动重新请求 ['getList', resource, pagination, sort, filter], () => dataProvider.getList(resource, { pagination, sort, filter }), { enabled: !!resource } ); return { ...listContext, aggs: rawResponse?.aggs || undefined, }; };
使用方式:在需要聚合数据的组件中替换useListContext为这个自定义Hook:
import { Datagrid, TextField } from 'react-admin'; import { useListWithAggs } from './useListWithAggs'; const MyListContent = () => { const { data, isLoading, aggs } = useListWithAggs(); // 用aggs渲染筛选或统计组件 return ( <> {aggs && <AggregationFilters aggs={aggs} />} <Datagrid isLoading={isLoading}> <TextField source="id" /> <TextField source="name" /> </Datagrid> </> ); }; // 页面层仍用原生List组件提供基础上下文 const MyListPage = () => ( <List resource="your-resource"> <MyListContent /> </List> );
优点:复用性强,所有需要聚合数据的组件都能直接使用;自动同步分页、排序、筛选参数的变化,确保聚合数据实时更新。
方案2:在组件中直接获取完整getList响应
如果只有单个组件需要聚合数据,无需封装Hook,直接用useQuery调用getList获取完整响应:
import { List, Datagrid, TextField, useListContext } from 'react-admin'; import { useQuery } from '@tanstack/react-query'; import { dataProvider } from './path-to-your-data-provider'; const MyListPage = () => { const { resource, pagination, sort, filter } = useListContext(); const { data: rawResponse, isLoading } = useQuery( ['getList', resource, pagination, sort, filter], () => dataProvider.getList(resource, { pagination, sort, filter }) ); const aggs = rawResponse?.aggs; return ( <div> {aggs && <AggregationFilters aggs={aggs} />} <List isLoading={isLoading}> <Datagrid> <TextField source="id" /> <TextField source="name" /> </Datagrid> </List> </div> ); };
优点:实现简单,无需额外封装;适合临时或单一组件的需求。
方案3:封装带聚合数据的自定义List组件
如果多个页面都需要聚合数据,可以封装一个全局可用的ListWithAggs组件,内部处理完整响应并将聚合数据通过自定义上下文或props传递:
import { List, ListContextProvider, useListContext } from 'react-admin'; import { useQuery } from '@tanstack/react-query'; import { dataProvider } from './path-to-your-data-provider'; export const ListWithAggs = ({ children, ...props }) => { const { resource, pagination, sort, filter } = useListContext(); const { data: rawResponse, isLoading, refetch } = useQuery( ['getList', resource, pagination, sort, filter], () => dataProvider.getList(resource, { pagination, sort, filter }) ); // 构建包含聚合数据的上下文值 const enhancedContext = { ...useListContext(), data: rawResponse?.objects || [], total: rawResponse?.total || 0, isLoading, refetch, aggs: rawResponse?.aggs || undefined, }; return ( <ListContextProvider value={enhancedContext}> <List {...props}> {children} </List> </ListContextProvider> ); };
使用方式:直接替换原生List组件:
import { Datagrid, TextField } from 'react-admin'; import { ListWithAggs } from './ListWithAggs'; const MyListPage = () => ( <ListWithAggs resource="your-resource"> {({ aggs }) => ( <> {aggs && <AggregationFilters aggs={aggs} />} <Datagrid> <TextField source="id" /> <TextField source="name" /> </Datagrid> </> )} </ListWithAggs> );
优点:全局统一处理,无需每个组件重复逻辑;保持与React-Admin原生List组件的API一致性。
注意事项
- 确保Query Key包含所有影响请求的参数(分页、排序、筛选),避免缓存导致的聚合数据不更新。
- 根据React-Admin版本调整
useQuery的用法(v4基于@tanstack/react-query,v3基于react-query v3)。 - 如果聚合数据体积较大,可以在dataProvider中添加缓存策略,减少重复请求。
内容的提问来源于stack exchange,提问作者benoit
相关产品推荐
相关产品推荐

