react-admin的matchSuggestion如何实现嵌套资源的匹配校验?
解决方案
方案1:前端预加载全量关联数据(适合数据量小的场景)
在渲染AutocompleteInput的父组件内提前拉取所有关联资源数据存入本地缓存,matchSuggestion直接从缓存读数据做匹配,不用发异步请求,符合同步函数要求。
import { useGetList, AutocompleteInput } from 'react-admin'; const QuoteInput = () => { // 提前拉取所有关联资源的全量数据 const { data: contacts } = useGetList('contacts', { pagination: { page: 1, perPage: 1000 } }); const { data: accounts } = useGetList('accounts', { pagination: { page: 1, perPage: 1000 } }); const { data: parts } = useGetList('parts', { pagination: { page: 1, perPage: 1000 } }); const matchAnyNested = (filter, quote) => { if (matchAnyField(filter, quote)) return true; // 直接从预加载缓存取关联数据 const contact = contacts?.find(c => c.id === quote.contact_id); if (contact && matchAnyField(filter, contact)) return true; const account = accounts?.find(a => a.id === contact?.account_id); if (account && matchAnyField(filter, account)) return true; for (let item of quote.part_items) { const part = parts?.find(p => p.id === item.part_id); if (part && matchAnyField(filter, part)) return true; } return false; }; return <AutocompleteInput source="quote_id" reference="quotes" matchSuggestion={matchAnyNested} /> };
方案2:后端侧做关联过滤(适合数据量大的生产场景,推荐)
不用前端的matchSuggestion做匹配,直接把过滤逻辑转移到后端。通过AutocompleteInput的filterToQuery属性把用户输入的关键词传给后端,后端联表查询关联的Contact、Address等资源,直接返回符合条件的Quote列表即可,前端不需要处理关联数据拉取逻辑。
import { AutocompleteInput } from 'react-admin'; const QuoteInput = () => { // 把用户输入内容转成后端可识别的过滤参数 const filterToQuery = (searchText) => ({ q: searchText, includeNested: ['contact', 'address'] }); // 无需传递matchSuggestion,后端已经返回过滤后的结果直接展示即可 return <AutocompleteInput source="quote_id" reference="quotes" filterToQuery={filterToQuery} /> };
方案3:自定义异步匹配逻辑(适合必须前端做异步查询的场景)
默认的matchSuggestion是同步函数,不支持异步请求,你可以封装自定义的Autocomplete组件,直接调用dataProvider的方法(不需要钩子,dataProvider本身是异步可直接调用)做关联查询,再过滤选项。
import { useDataProvider, useInput, Autocomplete } from 'react-admin'; import { useState, useEffect } from 'react'; const NestedMatchAutocompleteInput = (props) => { const dataProvider = useDataProvider(); const { field } = useInput(props); const [options, setOptions] = useState([]); const [filter, setFilter] = useState(''); // 监听输入关键词变化,异步查询关联数据做匹配 useEffect(() => { if (!filter) return; // 可先调用后端粗筛减少需要匹配的quote数量 dataProvider.getList('quotes', { pagination: { page:1, perPage: 100 } }) .then(async ({ data: quotes }) => { const matchedQuotes = []; for (const quote of quotes) { if (matchAnyField(filter, quote)) { matchedQuotes.push(quote); continue; } // 异步查询关联资源 const { data: contact } = await dataProvider.getOne('contacts', { id: quote.contact_id }); if (matchAnyField(filter, contact)) { matchedQuotes.push(quote); continue; } // 可继续扩展其他关联资源的匹配逻辑 } setOptions(matchedQuotes); }); }, [filter, dataProvider]); return <Autocomplete {...field} options={options} onInputChange={(e, v) => setFilter(v)} // 其他你需要的autocomplete配置项 /> };
注意:React钩子只能在组件顶层或者自定义钩子中调用,普通函数内不能使用useGetOne这类钩子,这个是React的强制规则,没有绕过的可能。
内容的提问来源于stack exchange,提问作者cr3at1ve
相关产品推荐
相关产品推荐

