如何通过ReferenceProvider实现多<SelectInput>共享同一数据源?
Great question! This is a super common pain point when working with multiple reference inputs that pull from the same resource—all those duplicate API requests can really drag down performance. Luckily, React Admin gives you a couple of solid ways to share a single data source across all 8 of your <SelectInput> components, eliminating redundant network calls.
Option 1: Fetch Data Once with useGetList (Simplest Approach)
The most straightforward fix is to use React Admin's useGetList hook to fetch your font data once, then pass the pre-fetched options to every <SelectInput>. This cuts your API requests from 8 down to 1.
Here's how to implement it:
import { useGetList, SelectInput, Form } from 'react-admin'; const FontConfigurationForm = () => { // Fetch all fonts in a single request const { data: fonts, isLoading, error } = useGetList('fonts', { pagination: { page: 1, perPage: 1000 }, // Adjust perPage if you have lots of fonts sort: { field: 'id', order: 'ASC' }, filter: {}, }); // Handle loading/error states if (isLoading) return <div>Loading font options...</div>; if (error) return <div>Failed to load fonts: {error.message}</div>; // Format data for SelectInput (matches your original optionText="id") const fontOptions = fonts.map(font => ({ id: font.id, name: font.id })); return ( <Form> {/* Primary font weights */} <SelectInput source="fonts.primary.regular" label="Primary Regular" options={fontOptions} /> <SelectInput source="fonts.primary.bold" label="Primary Bold" options={fontOptions} /> <SelectInput source="fonts.primary.light" label="Primary Light" options={fontOptions} /> <SelectInput source="fonts.primary.black" label="Primary Black" options={fontOptions} /> {/* Secondary font weights */} <SelectInput source="fonts.secondary.regular" label="Secondary Regular" options={fontOptions} /> <SelectInput source="fonts.secondary.bold" label="Secondary Bold" options={fontOptions} /> <SelectInput source="fonts.secondary.light" label="Secondary Light" options={fontOptions} /> <SelectInput source="fonts.secondary.black" label="Secondary Black" options={fontOptions} /> </Form> ); };
Pros & Cons
- Pros: No extra context setup, easy to understand, full control over data formatting.
- Cons: You lose some of React Admin's built-in reference input features (like automatic refetch on resource updates) unless you implement them manually.
Option 2: Use ReferenceContextProvider (React Admin-Native Approach)
If you want to stay closer to React Admin's ecosystem and retain features like automatic refetching, you can create a custom context provider using React Admin's internal ReferenceContextProvider. This lets all child <SelectInput> components share the same fetched data without duplicate requests.
Here's how to set this up:
import { ReferenceContextProvider, SelectInput, useGetList, Form } from 'react-admin'; // Custom provider to share font data const FontReferenceProvider = ({ children }) => { const { data: fonts, isLoading, error, refetch } = useGetList('fonts', { pagination: { page: 1, perPage: 1000 }, sort: { field: 'id', order: 'ASC' }, filter: {}, }); if (isLoading) return <div>Loading font options...</div>; if (error) return <div>Failed to load fonts: {error.message}</div>; // Format the context value to match React Admin's expected structure const referenceContext = { data: fonts, total: fonts.length, loaded: true, loading: false, error: null, refetch, }; return ( <ReferenceContextProvider value={referenceContext} resource="fonts"> {children} </ReferenceContextProvider> ); }; // Use the provider in your form const FontConfigurationForm = () => { return ( <FontReferenceProvider> <Form> {/* Primary font weights */} <SelectInput source="fonts.primary.regular" label="Primary Regular" optionText="id" /> <SelectInput source="fonts.primary.bold" label="Primary Bold" optionText="id" /> <SelectInput source="fonts.primary.light" label="Primary Light" optionText="id" /> <SelectInput source="fonts.primary.black" label="Primary Black" optionText="id" /> {/* Secondary font weights */} <SelectInput source="fonts.secondary.regular" label="Secondary Regular" optionText="id" /> <SelectInput source="fonts.secondary.bold" label="Secondary Bold" optionText="id" /> <SelectInput source="fonts.secondary.light" label="Secondary Light" optionText="id" /> <SelectInput source="fonts.secondary.black" label="Secondary Black" optionText="id" /> </Form> </FontReferenceProvider> ); };
Pros & Cons
- Pros: Integrates seamlessly with React Admin's lifecycle, retains automatic refetch capabilities, works with other reference-based inputs (like
AutocompleteInput). - Cons: Requires a bit more setup to match the context structure React Admin expects.
Bonus Tip: Bulk Set Default Values
Since you mentioned wanting to assign the same value to all fields when layout changes are minimal, you can add a button to set all inputs to a single selected font. Here's a quick example using React Admin's useForm hook:
import { useForm } from 'react-admin'; // Inside your form component const { change } = useForm(); const setAllFonts = (fontId) => { const fontFields = [ 'fonts.primary.regular', 'fonts.primary.bold', 'fonts.primary.light', 'fonts.primary.black', 'fonts.secondary.regular', 'fonts.secondary.bold', 'fonts.secondary.light', 'fonts.secondary.black', ]; fontFields.forEach(field => change(field, fontId)); }; // Add this button somewhere in your form <button onClick={() => setAllFonts('default-font-id')}>Set All Fonts to Default</button>
内容的提问来源于stack exchange,提问作者Hein Haraldson Berg

