React中实现点击+添加、X删除同款Div的问题咨询
解决方案
问题分析
原代码的核心问题:
handleAdd仅返回<IpRangeInput />组件,但未将其加入实际渲染列表- 删除按钮错误绑定了添加函数,无删除逻辑
- 每个输入组件独立管理自身状态,无法统一控制多输入项的增删
修正后的代码
通过状态提升将所有输入项的状态统一交给父组件管理,用数组存储输入项信息,父组件负责增删操作,子组件仅处理自身渲染和值更新。
完整代码实现
import { useState } from 'react'; import { Box, ThemeProvider, FormControl, Select, MenuItem, TextField, IconButton } from '@mui/material'; import AddIcon from '@mui/icons-material/Add'; import ClearIcon from '@mui/icons-material/Clear'; // 请替换为你的theme和styles路径 import theme from './your-theme-path'; import styles from './your-styles-path'; // 定义单个输入项的状态类型 type IpItem = { id: string; type: 'IP/CIDR' | 'Range' | ''; ipValue: string; fromValue: string; toValue: string; }; // 父组件:管理所有输入项的增删和状态 function IpRangeInputList() { // 初始化一个默认输入项 const [ipItems, setIpItems] = useState<IpItem[]>([{ id: Date.now().toString(), type: '', ipValue: '', fromValue: '', toValue: '' }]); // 添加新输入项 const handleAdd = () => { setIpItems(prev => [...prev, { id: Date.now().toString(), type: '', ipValue: '', fromValue: '', toValue: '' }]); }; // 删除指定输入项(至少保留一个) const handleDelete = (id: string) => { if (ipItems.length > 1) { setIpItems(prev => prev.filter(item => item.id !== id)); } }; // 更新单个输入项的状态 const updateIpItem = (id: string, updates: Partial<IpItem>) => { setIpItems(prev => prev.map(item => item.id === id ? {...item, ...updates} : item )); }; return ( <div> {ipItems.map(item => ( <IpRangeInput key={item.id} item={item} onUpdate={(updates) => updateIpItem(item.id, updates)} onDelete={() => handleDelete(item.id)} /> ))} <IconButton onClick={handleAdd} style={{marginTop: '16px'}}> <AddIcon /> </IconButton> </div> ); } // 子组件:负责单个输入项的渲染和交互 function IpRangeInput({ item, onUpdate, onDelete }) { return ( <Box className={styles.inputContainer}> <ThemeProvider theme={theme}> <FormControl className={styles.inputContainer__select}> <Select defaultValue="Select" id="select-label" value={item.type} onChange={(e) => onUpdate({type: e.target.value as 'IP/CIDR' | 'Range'})} > <MenuItem value="IP/CIDR">IP / CIDR</MenuItem> <MenuItem value="Range">Range</MenuItem> </Select> </FormControl> {item.type === 'Range' ? ( <> <span className={styles.inputContainer__text}>From</span> <Box className={[ styles.inputContainer__input, styles.inputContainer__newInput, ].join(' ')} > <TextField value={item.fromValue} onChange={(e) => onUpdate({fromValue: e.target.value})} /> </Box> <span className={styles.inputContainer__text}>To</span> <Box className={[ styles.inputContainer__input, styles.inputContainer__newInput, ].join(' ')} > <TextField value={item.toValue} onChange={(e) => onUpdate({toValue: e.target.value})} /> </Box> </> ) : ( <Box className={styles.inputContainer__input}> <TextField value={item.ipValue} onChange={(e) => onUpdate({ipValue: e.target.value})} /> </Box> )} <IconButton className={styles.inputContainer__clearButton} onClick={onDelete} > <ClearIcon /> </IconButton> </ThemeProvider> </Box> ); } export default IpRangeInputList;
关键改动说明
- 状态统一管理:父组件用数组存储所有输入项状态,避免子组件独立状态导致的增删失控
- 唯一标识:每个输入项添加
id作为React列表渲染的唯一key,保证渲染稳定性 - 增删逻辑:
handleAdd向数组追加新输入项;handleDelete通过id过滤删除目标项,同时限制至少保留一个输入项 - 子组件通信:通过props传递更新和删除函数,子组件仅负责触发操作,不管理全局状态
- 修正绑定错误:删除按钮绑定正确的删除函数,解决原代码中绑定错误的问题
内容的提问来源于stack exchange,提问作者Stiven Ballshi
相关产品推荐
相关产品推荐

