React Admin中不使用ArrayInput存储数组输入的实现咨询
在React Admin中不使用ArrayInput实现数组数据输入方案
完全可以通过自定义字段组件结合React Admin的表单钩子实现需求,以下是具体方案:
核心思路
利用React Admin集成的react-hook-form能力,通过useForm钩子读写表单状态,自定义UI组件(MUI Select、日期选择器、价格输入框)收集数据,手动维护oilPrice和gasPrice数组的状态,提交时自动整理为目标数据结构,且天然支持切换类型时的持久化。
实现步骤
- 封装自定义字段组件,整合类型选择、日期选择、价格输入及数据管理逻辑
- 通过
useForm的getValues/setValue方法维护表单内的数组数据 - 处理数据添加、删除逻辑,避免重复日期数据
- 在Create页面中引入自定义字段组件
代码示例
自定义价格数组字段组件
import React, { useState } from 'react'; import { useForm } from 'react-hook-form'; import { Select, MenuItem, TextField, Button, Box, Typography } from '@mui/material'; import DatePicker from '@mui/lab/DatePicker'; import AdapterDateFns from '@mui/lab/AdapterDateFns'; import LocalizationProvider from '@mui/lab/LocalizationProvider'; const PriceArrayField = () => { const { getValues, setValue } = useForm({ defaultValues: { data: { oilPrice: [], gasPrice: [] } } }); const [selectedType, setSelectedType] = useState('oil'); const [tempDate, setTempDate] = useState(null); const [tempPrice, setTempPrice] = useState(''); // 获取当前类型的已输入数据 const currentPrices = getValues(`data.${selectedType}Price`) || []; // 格式化日期为DD.MM.YYYY格式 const formatDate = (date) => { if (!date) return ''; const day = String(date.getDate()).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0'); const year = date.getFullYear(); return `${day}.${month}.${year}`; }; // 添加价格数据到对应数组 const handleAddPrice = () => { if (!tempDate || !tempPrice) return; const formattedDay = formatDate(tempDate); // 校验重复日期 if (currentPrices.some(item => item.day === formattedDay)) { alert('该日期的价格已存在'); return; } const newPriceArray = [ ...currentPrices, { day: formattedDay, price: Number(tempPrice) } ]; setValue(`data.${selectedType}Price`, newPriceArray); // 清空临时输入 setTempDate(null); setTempPrice(''); }; // 删除单条价格数据 const handleRemovePrice = (index) => { const newPriceArray = currentPrices.filter((_, i) => i !== index); setValue(`data.${selectedType}Price`, newPriceArray); }; return ( <Box sx={{ mt: 2 }}> {/* 价格类型选择器 */} <Select value={selectedType} onChange={(e) => setSelectedType(e.target.value)} sx={{ mb: 2, minWidth: 150 }} > <MenuItem value="oil">Oil</MenuItem> <MenuItem value="gas">Gas</MenuItem> </Select> {/* 日期与价格输入区 */} <LocalizationProvider dateAdapter={AdapterDateFns}> <Box sx={{ display: 'flex', gap: 2, mb: 2 }}> <DatePicker label="选择日期" value={tempDate} onChange={(newValue) => setTempDate(newValue)} renderInput={(params) => <TextField {...params} />} /> <TextField label="输入价格" type="number" value={tempPrice} onChange={(e) => setTempPrice(e.target.value)} /> <Button variant="contained" onClick={handleAddPrice}>添加</Button> </Box> </LocalizationProvider> {/* 已输入数据展示 */} <Typography variant="subtitle1" sx={{ mb: 1 }}> 已输入{selectedType === 'oil' ? '油价' : '气价'}: </Typography> {currentPrices.length > 0 ? ( <Box sx={{ mb: 2 }}> {currentPrices.map((item, index) => ( <Box key={index} sx={{ display: 'flex', gap: 2, alignItems: 'center', mb: 1 }}> <Typography>{item.day}: {item.price}</Typography> <Button variant="outlined" size="small" onClick={() => handleRemovePrice(index)}>删除</Button> </Box> ))} </Box> ) : ( <Typography sx={{ mb: 2 }}>暂无数据</Typography> )} </Box> ); }; export default PriceArrayField;
在Create页面中使用自定义字段
import React from 'react'; import { Create, SimpleForm, TextInput } from 'react-admin'; import PriceArrayField from './PriceArrayField'; const PriceCreate = () => { return ( <Create title="创建价格数据"> <SimpleForm> <TextInput source="id" /> <PriceArrayField /> </SimpleForm> </Create> ); }; export default PriceCreate;
持久化说明
由于所有数据都存储在React Admin表单的内部状态中,切换Oil/Gas类型时,oilPrice和gasPrice数组会被完整保留,不会丢失已输入数据。提交表单时,数据会自动以{ id, data: { oilPrice: [...], gasPrice: [...] } }的结构发送到后端,完全符合需求。
内容的提问来源于stack exchange,提问作者Oleksandra Krupnova
相关产品推荐
相关产品推荐

