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

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;
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;

问题根源

  1. resorts未作为React状态管理:直接声明的const resorts = new Map()不是状态变量,每次组件渲染时都会重新创建新的Map实例,修改后不会触发组件重渲染,子组件也无法获取更新后的数据。
  2. formData初始值错误:longitude: Number和latitude: Number是把构造函数作为值,输入框会显示异常内容,应该设为0或空字符串。
  3. 删除选项的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;
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:05:33