React 18.2中从子组件修改父组件Map失败,求技术支持
React 18.2 子组件修改父组件Map数据无效的解决方法
问题说明
在React 18.2中尝试通过子组件(模态框表单)修改父组件内的Map数据,执行添加或删除操作后未达到预期效果。父组件包含模态框,表单支持选择添加/删除操作并输入对应数据,但修改后Map数据未更新,子组件也无法感知变化。
原代码
Parent.js
const ParentComponent = ({show, onCloseModalButton}) => { const resorts = new Map() resorts.set("Keystone", [39.6069742, -105.97011]) resorts.set("Breckenridge", [39.4808, -106.0676]) resorts.set("Vail", [39.6061, -106.3550]) resorts.set("Crested Butte", [38.8991, -106.9658]) resorts.set("Winter Park", [39.8841, -105.7627]) resorts.set("Copper Mountain", [39.5022, -106.1497]) const [formOption, setFormOption] = React.useState("") const [formData, setFormData] = React.useState({ resortName: "", longitude: Number, latitude: Number, }) const handleOptionChange = e => { setFormOption(e.target.value) } const handleFormDataChange = e => { setFormData({ ...formData, [e.target.name]: e.target.value, }) } const submitForm = e => { e.preventDefault() if (formOption === "Add") { resorts.set(formData.resortName, [formData.latitude, formData.longitude]) } if (formOption === "Delete") { resorts.delete(formData.resortName) } } return ( <div> <Modal show={show} onCloseModalButton={onCloseModalButton} resorts={resorts} submitForm={submitForm} handleOptionChange={handleOptionChange} handleFormChange={handleFormDataChange} option={formOption} form={formData} /> </div> ) } export default ParentComponent;
Modal.js
const Modal = ({show, onCloseModalButton, resorts, submitForm, handleOptionChange, handleFormChange, option, form}) => { if (!show) { return null } return ReactDOM.createPortal ( <div className='modal-bg'> <div className='modal'> <form onSubmit={submitForm}> <label>Modify: <select name="option" value={option} onChange={handleOptionChange} > <option value="" disabled={true}>-- Choose an Option --</option> <option value="Add">Add</option> <option value="Delete">Delete</option> </select> </label> {option === "" ? null : option === "Add" ? <div> <label>Resort Name <input type="text" name="resortName" value={form.resortName} onChange={handleFormChange} /> </label> <br></br> <label>Longitude <input type="number" name="longitude" value={form.longitude} onChange={handleFormChange} /> </label> <br></br> <label>Latitude <input type="number" name="latitude" value={form.latitude} onChange={handleFormChange} /> </label> <button type='submit'>Submit</button> </div> : <div> <label>Delete <select name="delete" value={form.resortName} onChange={handleFormChange} > {[...resorts.keys()].map((item)=> { return <option key={item} value={item}>{item}</option> })} </select> </label> <button type='submit'>Submit</button> </div> } </form> <button onClick={onCloseModalButton}>Close Modal</button> </div> </div> , document.body ) } export default Modal;
问题根源
- resorts未作为React状态管理:直接声明的
const resorts = new Map()不是状态变量,每次组件渲染时都会重新创建新的Map实例,修改后不会触发组件重渲染,子组件也无法获取更新后的数据。 - formData初始值错误:
longitude: Number和latitude: Number是把构造函数作为值,输入框会显示异常内容,应该设为0或空字符串。 - 删除选项的select名称错误:Modal中删除操作的select的
name="delete",导致handleFormChange更新的是formData的delete字段,而非resortName,删除时无法正确获取要删除的名称。
修复后的代码
Parent.js
const ParentComponent = ({show, onCloseModalButton}) => { // 将resorts改为React状态,用初始化函数确保只执行一次 const [resorts, setResorts] = React.useState(() => { const map = new Map() map.set("Keystone", [39.6069742, -105.97011]) map.set("Breckenridge", [39.4808, -106.0676]) map.set("Vail", [39.6061, -106.3550]) map.set("Crested Butte", [38.8991, -106.9658]) map.set("Winter Park", [39.8841, -105.7627]) map.set("Copper Mountain", [39.5022, -106.1497]) return map }) const [formOption, setFormOption] = React.useState("") // 修正formData初始值,将Number改为0 const [formData, setFormData] = React.useState({ resortName: "", longitude: 0, latitude: 0, }) const handleOptionChange = e => { setFormOption(e.target.value) } const handleFormDataChange = e => { setFormData({ ...formData, [e.target.name]: e.target.value, }) } const submitForm = e => { e.preventDefault() if (formOption === "Add") { // 修改Map时创建新实例,触发状态更新 setResorts(prevResorts => { const newMap = new Map(prevResorts) // 转换为数字类型,输入框值默认是字符串 newMap.set(formData.resortName, [Number(formData.latitude), Number(formData.longitude)]) return newMap }) } if (formOption === "Delete") { // 删除时同样创建新Map实例 setResorts(prevResorts => { const newMap = new Map(prevResorts) newMap.delete(formData.resortName) return newMap }) } // 提交后重置表单 setFormOption("") setFormData({resortName: "", longitude: 0, latitude: 0}) } return ( <div> <Modal show={show} onCloseModalButton={onCloseModalButton} resorts={resorts} submitForm={submitForm} handleOptionChange={handleOptionChange} handleFormChange={handleFormDataChange} option={formOption} form={formData} /> </div> ) } export default ParentComponent;
Modal.js
const Modal = ({show, onCloseModalButton, resorts, submitForm, handleOptionChange, handleFormChange, option, form}) => { if (!show) { return null } return ReactDOM.createPortal ( <div className='modal-bg'> <div className='modal'> <form onSubmit={submitForm}> <label>Modify: <select name="option" value={option} onChange={handleOptionChange} > <option value="" disabled={true}>-- Choose an Option --</option> <option value="Add">Add</option> <option value="Delete">Delete</option> </select> </label> {option === "" ? null : option === "Add" ? <div> <label>Resort Name <input type="text" name="resortName" value={form.resortName} onChange={handleFormChange} /> </label> <br></br> <label>Longitude <input type="number" name="longitude" value={form.longitude} onChange={handleFormChange} /> </label> <br></br> <label>Latitude <input type="number" name="latitude" value={form.latitude} onChange={handleFormChange} /> </label> <button type='submit'>Submit</button> </div> : <div> <label>Delete {/* 修正select的name为resortName,确保更新formData.resortName */} <select name="resortName" value={form.resortName} onChange={handleFormChange} > {[...resorts.keys()].map((item)=> { return <option key={item} value={item}>{item}</option> })} </select> </label> <button type='submit'>Submit</button> </div> } </form> <button onClick={onCloseModalButton}>Close Modal</button> </div> </div> , document.body ) } export default Modal;
关键修复说明
- 状态化Map数据:使用
useState管理resorts,通过创建新的Map实例修改数据,确保触发React的重渲染机制,子组件能同步获取最新数据。 - 修正表单初始值:将经度纬度的初始值改为数字0,避免输入框显示异常内容。
- 统一表单字段名称:删除操作的select名称改为resortName,确保表单数据正确绑定,删除时能获取到目标度假村名称。
- 类型转换:添加时将输入框的字符串值转为数字,符合Map中存储的坐标数据类型。
内容的提问来源于stack exchange,提问作者Grant
相关产品推荐
相关产品推荐

