import React, { useEffect, useState } from 'react'; import { Row, Col, Input, Button } from 'antd'; import { PlusOutlined, DeleteOutlined } from '@ant-design/icons'; import './KeyValueList.css'; export type DictValue = Record; type KeyValuePair = { id: string; k: string; v: string }; type Props = { value?: DictValue; onChange?: (value: DictValue) => void; }; const KeyValueList: React.FC = ({ value, onChange }) => { const [rows, setRows] = useState([]); useEffect(() => { // 初始化时提供一行空输入;之后只合并父值,不再自动新增空行 const initializedRef = (KeyValueList as any)._initializedRef || { current: false }; (KeyValueList as any)._initializedRef = initializedRef; setRows((prev) => { const existingIdByKey = new Map(prev.filter((r) => r.k).map((r) => [r.k, r.id])); const valuePairs: KeyValuePair[] = value ? Object.keys(value).map((key) => ({ id: existingIdByKey.get(key) || `${key}-${Date.now()}-${Math.random().toString(36).slice(2)}`, k: key, v: value[key] ?? '', })) : []; const blankRows = prev.filter((r) => !r.k); let merged = [...valuePairs, ...blankRows]; if (!initializedRef.current && merged.length === 0) { merged = [{ id: `row-${Date.now()}-${Math.random().toString(36).slice(2)}`, k: '', v: '' }]; } initializedRef.current = true; return merged; }); }, [value]); const emitChange = (nextRows: KeyValuePair[]) => { const dict: DictValue = {}; nextRows.forEach((r) => { if (r.k && r.k.trim() !== '') { dict[r.k] = r.v ?? ''; } }); onChange?.(dict); }; const updateRow = (id: string, field: 'k' | 'v', val: string) => { const next = rows.map((r) => (r.id === id ? { ...r, [field]: val } : r)); setRows(next); emitChange(next); }; const addRow = () => { const next = [...rows, { id: `row-${Date.now()}-${Math.random().toString(36).slice(2)}`, k: '', v: '' }]; setRows(next); // 不触发 onChange,因为字典未变化(空行不入字典) }; const removeRow = (id: string) => { const removed = rows.find((r) => r.id === id); const next = rows.filter((r) => r.id !== id); setRows(next); if (removed?.k && removed.k.trim() !== '') { emitChange(next); } }; return (
{rows.map((r) => (
updateRow(r.id, 'k', e.target.value)} /> updateRow(r.id, 'v', e.target.value)} />
))}
); }; export default KeyValueList;