React.js中Modal提交后所有列表项状态都变更而非仅选中项如何解决
问题根因
你当前的代码存在两个核心问题导致所有时间段同步修改:
- 所有时间段共用全局唯一的
name和phoneNumber状态,只要这两个值更新,所有引用这两个状态的时间段节点都会同步渲染最新值 - 点击时间段打开模态框时,没有记录当前选中的是哪个时间段,提交表单时无法定位到要修改的目标时间段,只能修改全局共用的状态
修复方案
改造思路
- 替换单一的用户信息状态为时间段数组,每个时间段独立存储自己的预约信息
- 新增状态记录当前激活的时间段ID,点击打开模态框时赋值
- 表单提交时只更新激活ID对应的时间段数据,不修改全局共用变量
- 遍历时间段数组渲染列表,避免重复写死节点代码
修复后完整代码
import React, {useState} from 'react' import './App.css'; import Modal from 'react-modal'; Modal.setAppElement('#root') function App() { const [modalIsOpen, setModalIsOpen] = useState(false); // 时间段数组,每个项独立存储对应时段的预约信息 const [timeSlots, setTimeSlots] = useState([ {id: 1, time: '9:00am', name: '', phoneNumber: ''}, {id: 2, time: '10:00am', name: '', phoneNumber: ''} ]); // 记录当前选中的时间段ID const [activeSlotId, setActiveSlotId] = useState(null); // 表单临时状态,仅用于模态框输入暂存 const [formName, setFormName] = useState(""); const [formPhone, setFormPhone] = useState(""); const handleSubmit = (e) => { e.preventDefault(); // 仅更新选中ID对应的时间段数据 setTimeSlots(prevSlots => prevSlots.map(slot => { if (slot.id === activeSlotId) { return {...slot, name: formName, phoneNumber: formPhone} } return slot })) // 提交后重置状态 setModalIsOpen(false); setFormName(""); setFormPhone(""); } return ( <div className="App"> <h2>Hello world</h2> <Modal isOpen={modalIsOpen} onRequestClose={() => setModalIsOpen(false)}> <form onSubmit={handleSubmit}> <input type="text" required name="name" placeholder="enter full name" value={formName} onChange={(e)=> setFormName(e.target.value)} /> <input type="number" name="phoneNumber" required maxLength="10" value={formPhone} placeholder="enter phone number" onChange={(e)=> setFormPhone(e.target.value)} /> <button type="submit">Confirm</button> </form> </Modal> <div className="time-slot-list"> <ul> {/* 遍历数组渲染所有时间段,后续新增时段只需修改timeSlots数组即可 */} {timeSlots.map(slot => ( <li key={slot.id} className={`time-slot ${slot.name ? 'redBg' : ''}`} onClick={() => { setActiveSlotId(slot.id) // 已预约的时段打开模态框时自动回填数据 setFormName(slot.name) setFormPhone(slot.phoneNumber) setModalIsOpen(true) }} > {slot.time} {slot.name && <p>{slot.name}</p>} </li> ))} </ul> </div> </div> ); } export default App;
内容的提问来源于stack exchange,提问作者wadaygo2
相关产品推荐
相关产品推荐

