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

MERN栈React Redux如何传递预约ID到提交函数并正确派发action

问题根因

  • 参数传递错误:handleSubmit 定义要求第一个参数为事件对象 e、第二个为预约ID,但按钮点击回调仅传入了预约ID,导致执行 e.preventDefault() 时直接抛出 undefined 报错,逻辑中断
  • 表单状态全局共享:所有预约条目共用同一个 reasonForMassage 状态,修改任意一条的输入内容会同步覆盖所有条目的值,无法拿到当前提交预约对应的表单数据
  • 表单字段收集不全:同意按摩区域复选框、禁忌按摩区域输入值未做状态管理,提交时这些数据会丢失
  • 表单默认行为未处理:提交按钮默认是 submit 类型,未显式指定类型时可能触发原生表单提交,导致页面刷新

修复后的完整代码

import React, { useState } from 'react'
import { useDispatch } from 'react-redux'
import { confirmAppointment } from '../../../actions/appointment'

const ConfirmAppointment = ({user}) => {
    const dispatch = useDispatch()
    // 重命名用户ID为userId,避免和预约ID混淆
    const { appointments, _id: userId } = user?.result ?? {}
    const today = new Date()

    // 按预约ID存储对应表单数据,隔离各条目的状态
    const [formState, setFormState] = useState({})

    // 普通输入框值更新逻辑
    const handleFieldChange = (appointmentId, field, value) => {
        setFormState(prev => ({
            ...prev,
            [appointmentId]: {
                ...prev[appointmentId],
                [field]: value
            }
        }))
    }

    // 复选框值更新逻辑
    const handleCheckboxChange = (appointmentId, area, checked) => {
        setFormState(prev => ({
            ...prev,
            [appointmentId]: {
                ...prev[appointmentId],
                consentAreas: {
                    ...prev[appointmentId]?.consentAreas,
                    [area]: checked
                }
            }
        }))
    }

    const handleSubmit = (e, appointmentId) => {
        e.preventDefault()
        const currentFormData = formState[appointmentId] ?? {}
        console.log(appointmentId, currentFormData)
        dispatch(confirmAppointment(userId, appointmentId, currentFormData))
    }

    if (!appointments?.length) {
        return <div>No upcoming appointments</div>
    }

    return (
        <div style={{marginTop: '3em'}}>
            <h4>Upcoming Appointments</h4>
            {appointments.map((appointment) => {
                // 过期预约直接跳过渲染
                if (new Date(appointment?.date) < today) return null
                const currentForm = formState[appointment._id] ?? {}
                return (
                    <div style={{marginBottom: '3em'}} key={appointment._id} >
                        <table className="ui table">
                            <thead>
                                <tr>
                                    <th>Date</th>
                                    <th>Time</th>
                                    <th>Duration</th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr>
                                    <td>{appointment?.date}</td>
                                    <td>{appointment?.time}</td>
                                    <td>{appointment?.duration}</td>
                                </tr>
                            </tbody>
                        </table>
                        <form className="ui form">
                            <div className="ui fields">
                                <div className="ui field">
                                    <label>Reason for booking massage:</label>
                                    <input 
                                        type="text" 
                                        value={currentForm.reasonForMassage ?? ''} 
                                        onChange={(e)=>handleFieldChange(appointment._id, 'reasonForMassage', e.target.value)}
                                    />
                                </div>
                                <div className="ui field">
                                    <h5>I give consent to massage the following areas:</h5>
                                    <div>
                                        <input 
                                            type="checkbox" 
                                            checked={currentForm.consentAreas?.glutes ?? false}
                                            onChange={(e) => handleCheckboxChange(appointment._id, 'glutes', e.target.checked)}
                                        />
                                        <label>Glutes</label>
                                        <input 
                                            type="checkbox" 
                                            checked={currentForm.consentAreas?.abdomen ?? false}
                                            onChange={(e) => handleCheckboxChange(appointment._id, 'abdomen', e.target.checked)}
                                        />
                                        <label>Abdomen</label>
                                        <input 
                                            type="checkbox" 
                                            checked={currentForm.consentAreas?.chest ?? false}
                                            onChange={(e) => handleCheckboxChange(appointment._id, 'chest', e.target.checked)}
                                        />
                                        <label>Chest</label>
                                        <input 
                                            type="checkbox" 
                                            checked={currentForm.consentAreas?.innerThighs ?? false}
                                            onChange={(e) => handleCheckboxChange(appointment._id, 'innerThighs', e.target.checked)}
                                        />
                                        <label>Inner thighs</label>
                                    </div>
                                </div>
                                <div className="ui field">
                                    <label>Are there any other areas you would not like to be massaged?</label>
                                    <input 
                                        type="text" 
                                        value={currentForm.forbiddenAreas ?? ''}
                                        onChange={(e) => handleFieldChange(appointment._id, 'forbiddenAreas', e.target.value)}
                                    />
                                </div>
                            </div>
                            <button 
                                type="button"
                                onClick={(e)=>handleSubmit(e, appointment._id)} 
                                className="ui button"
                            >
                                Confirm Appointment
                            </button>
                        </form>                                
                    </div>
                )
            })}                 
        </div>
    )
}

export default ConfirmAppointment

内容的提问来源于stack exchange,提问作者Cip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 01:45:00