React-Admin如何实现筛选器仅展示当前结果关联选项?
你提到的需求可以通过React-Admin自带的上下文和组件属性实现,无需仅依赖DataProvider层,以下是几种更贴合框架特性的方案:
方案1:利用List上下文传递筛选条件到ReferenceArrayInput
React-Admin的useListContext可以获取当前List组件的筛选状态,你可以在自定义Filter组件中拿到这些条件,传递给<ReferenceArrayInput>,让下拉选项的查询自动带上对应条件,只返回与当前筛选结果匹配的国家。
示例代码:
import { Filter, ReferenceArrayInput, SelectArrayInput, useListContext } from 'react-admin'; const CustomFilter = (props) => { const { filters } = useListContext(); // 获取当前List的筛选条件 return ( <Filter {...props}> {/* 其他筛选组件 */} <ReferenceArrayInput source="country_ids" reference="countries" // 根据当前List的筛选条件动态过滤下拉选项 filter={{ // 示例:如果List按订单状态筛选,这里过滤出有对应状态订单的国家 ...(filters.status && { has_orders_with_status: filters.status }) }} > <SelectArrayInput optionText="name" /> </ReferenceArrayInput> </Filter> ); }; // 在List组件中使用自定义Filter export const OrderList = () => ( <List filters={<CustomFilter />}> {/* List内容 */} </List> );
这个方案复用List的筛选条件,让关联资源的查询和主List保持逻辑一致,确保下拉选项仅包含符合当前筛选规则的结果。
方案2:通过queryOptions自定义查询逻辑(React-Admin v4+)
如果使用React-Admin v4及以上版本(基于react-query实现数据请求),可以通过<ReferenceArrayInput>的queryOptions属性,结合List上下文的筛选条件动态修改查询参数:
import { Filter, ReferenceArrayInput, SelectArrayInput, useListContext, dataProvider } from 'react-admin'; const CustomFilter = (props) => { const { filters } = useListContext(); return ( <Filter {...props}> <ReferenceArrayInput source="country_ids" reference="countries" queryOptions={{ queryKey: ['countries', 'filter', filters], // 筛选变化时自动重新查询 queryFn: async ({ queryKey }) => { const [, , currentFilters] = queryKey; // 调用dataProvider自定义查询逻辑 return dataProvider.getList('countries', { filter: { ...(currentFilters.status && { order_status: currentFilters.status }) }, pagination: { page: 1, perPage: 100 }, sort: { field: 'name', order: 'ASC' } }); } }} > <SelectArrayInput optionText="name" /> </ReferenceArrayInput> </Filter> ); };
这种方式灵活性更高,适合需要复杂查询逻辑的场景,完全基于React-Admin的组件能力实现。
方案3:基于当前List结果集提取关联选项
如果需求是严格基于当前List已加载的结果集显示关联国家(而非通过筛选条件推导),可以先获取当前List的数据,提取所有关联的国家ID,再让<ReferenceArrayInput>仅查询这些ID:
import { Filter, ReferenceArrayInput, SelectArrayInput, useListContext } from 'react-admin'; const CustomFilter = (props) => { const { data: listData } = useListContext(); // 获取当前List加载的数据 // 提取所有数据中的国家ID const countryIds = listData?.reduce((acc, item) => { item.country_ids.forEach(id => acc.add(id)); return acc; }, new Set()); return ( <Filter {...props}> <ReferenceArrayInput source="country_ids" reference="countries" filter={{ id: Array.from(countryIds) }} // 仅查询指定ID的国家 queryOptions={{ enabled: !!listData, queryKey: ['countries', 'filtered_ids', countryIds] }} > <SelectArrayInput optionText="name" /> </ReferenceArrayInput> </Filter> ); };
注意:该方案仅适用于List数据全部加载的场景(如关闭分页或数据量较小),若List为分页加载,仅会显示当前页数据关联的国家,需根据实际场景调整。
以上方案均比直接在DataProvider中硬编码逻辑更贴合React-Admin的设计,利用了框架的上下文、组件属性和数据请求机制,代码更内聚、易维护。
内容的提问来源于stack exchange,提问作者ianmayo

