You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Admin中不使用ArrayInput存储数组输入的实现咨询

在React Admin中不使用ArrayInput实现数组数据输入方案

完全可以通过自定义字段组件结合React Admin的表单钩子实现需求,以下是具体方案:

核心思路

利用React Admin集成的react-hook-form能力,通过useForm钩子读写表单状态,自定义UI组件(MUI Select、日期选择器、价格输入框)收集数据,手动维护oilPrice和gasPrice数组的状态,提交时自动整理为目标数据结构,且天然支持切换类型时的持久化。

实现步骤

  1. 封装自定义字段组件,整合类型选择、日期选择、价格输入及数据管理逻辑
  2. 通过useForm的getValues/setValue方法维护表单内的数组数据
  3. 处理数据添加、删除逻辑,避免重复日期数据
  4. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 12:15:32