如何用useReducer实现表单中根据选中日期更新可用时间?
问题:如何实现根据选中日期更新表单时间选项的updateTimes函数?
需求说明
步骤2:更新BookingForm以根据选中日期显示可用时间
- 将availableTimes状态改为reducer
- 在Main组件中创建
updateTimes函数,根据选中日期更改availableTimes(目前可先返回固定时间)- 创建
initializeTimes函数生成availableTimes初始状态- 使用
useReducer管理availableTimes状态- 更新BookingForm,在日期字段变更时触发dispatch更新时间
现有代码
表单reducer
const formReducer= (state, event) => { return { ...state, [event.name]: event.value } }
BookingForm组件
function Bookingform(props){ const [formData, setFormData] = useReducer(formReducer, {}); const [submitting, setSubmitting] = useState(); const times = [ {value: "17:00", text: "17:00" }, {value: "18:00", text: "18:00" }, {value: "19:00", text: "19:00" }, {value: "20:00", text: "20:00" }, {value: "21:00", text: "21:00" }, {value: "22:00", text: "22:00" }, ] const handleSubmit = (e) => { e.preventDefault(); setSubmitting(true); props.onSubmit(formData); setTimeout (() => { setSubmitting(false); }, 3000) }; const handleChange = event => { const isCheckbox = event.target.type === "checkbox"; setFormData({ name: event.target.name, value: event.target.value, value: isCheckbox ? event.target.checked : event.target.value, }); } return ( <div className="Wrapper"> <h1>Reserve a Table</h1> <form onSubmit={handleSubmit}> <fieldset> <field name="field" value={field}> <label> <p>Time</p> <select name="Time" onChange={handleChange}> {times.map((option, index) => ( <option key={index} value={option.value}> {option.text} </option> ))} </select> </label> <label> <p>Date</p> <input type="date" name="Date" onChange={handleChange}/> </label> <label> <p>Guests</p> <input type="number" name="Count" min="1" max="9" onChange={handleChange} step="1"/> </label> <label> <p>Choose Occasion</p> <select name="Occasion" onChange={handleChange}> <option>Anniversary</option> <option>Birthday</option> </select> </label> <button type="submit">Submit</button> </field> </fieldset> </form> </div> ) }
分步实现方案
1. 定义时间状态的reducer函数
在Main组件中创建初始化和更新时间的函数:
// 生成初始可用时间列表 const initializeTimes = () => [ {value: "17:00", text: "17:00" }, {value: "18:00", text: "18:00" }, {value: "19:00", text: "19:00" }, {value: "20:00", text: "20:00" }, {value: "21:00", text: "21:00" }, {value: "22:00", text: "22:00" }, ]; // 处理时间状态更新的reducer const updateTimes = (state, action) => { switch(action.type) { case 'UPDATE_TIMES': // 这里可根据action.payload(选中的日期)编写动态时间逻辑 // 当前先返回固定时间,后续可扩展(比如周末多开放时段) return initializeTimes(); default: // 未知action类型时返回原状态 return state; } };
2. 在Main组件中用useReducer管理时间状态
初始化reducer,并将时间状态和更新函数传递给BookingForm:
import { useReducer } from 'react'; function Main() { // 用useReducer初始化时间状态,第三个参数是初始化函数 const [availableTimes, dispatch] = useReducer(updateTimes, undefined, initializeTimes); return ( <div> <Bookingform availableTimes={availableTimes} // 传递日期变更时触发的函数,用于dispatch更新时间 onDateChange={(selectedDate) => { dispatch({ type: 'UPDATE_TIMES', payload: selectedDate }); }} // 保留原有的onSubmit回调 onSubmit={/* 你的提交逻辑 */} /> </div> ); }
3. 修改BookingForm组件适配新状态
移除硬编码的times数组,改用父组件传入的availableTimes,并在日期变更时触发更新:
import { useReducer, useState } from 'react'; const formReducer= (state, event) => { return { ...state, [event.name]: event.value } } function Bookingform(props){ const [formData, setFormData] = useReducer(formReducer, {}); const [submitting, setSubmitting] = useState(false); // 从props获取可用时间 const times = props.availableTimes; const handleSubmit = (e) => { e.preventDefault(); setSubmitting(true); props.onSubmit(formData); setTimeout (() => { setSubmitting(false); }, 3000) }; const handleChange = event => { const isCheckbox = event.target.type === "checkbox"; const value = isCheckbox ? event.target.checked : event.target.value; setFormData({ name: event.target.name, value: value, }); // 检测日期字段变更,触发父组件的时间更新 if(event.target.name === "Date") { props.onDateChange(event.target.value); } } return ( <div className="Wrapper"> <h1>Reserve a Table</h1> <form onSubmit={handleSubmit}> <fieldset> {/* 移除原错误的<field>标签 */} <label> <p>Time</p> <select name="Time" onChange={handleChange} value={formData.Time || ""}> {times.map((option, index) => ( <option key={index} value={option.value}> {option.text} </option> ))} </select> </label> <label> <p>Date</p> <input type="date" name="Date" onChange={handleChange} value={formData.Date || ""}/> </label> <label> <p>Guests</p> <input type="number" name="Count" min="1" max="9" onChange={handleChange} step="1" value={formData.Count || 1}/> </label> <label> <p>Choose Occasion</p> <select name="Occasion" onChange={handleChange} value={formData.Occasion || ""}> <option value="Anniversary">Anniversary</option> <option value="Birthday">Birthday</option> </select> </label> <button type="submit" disabled={submitting}> {submitting ? "Submitting..." : "Submit"} </button> </fieldset> </form> </div> ) }
关键细节说明
- 状态提升:将时间状态放在Main组件管理,符合React单向数据流原则,方便后续扩展(比如从API拉取可用时间)。
- reducer逻辑:
updateTimes通过action类型区分操作,后续只需修改case分支,就能实现根据不同日期返回不同时间的逻辑。 - 表单优化:给所有表单控件添加
value绑定formData,转为受控组件,避免状态不一致;修复原代码中无效的<field>标签;添加提交按钮禁用状态,防止重复提交。
内容的提问来源于stack exchange,提问作者Oh Wire
相关产品推荐
相关产品推荐

