React中如何维护各日期时段输入的父组件状态?单/多onChange实现问询
用单个
onChange函数实现星期时间输入的状态更新 当然可以用单个onChange函数搞定这个需求!这其实是React里处理表单输入很常见的模式,既简洁又易维护。下面我会一步步修改你的代码,实现将输入值按monday: {startTime: '08:00', endTime: '23:00'}的格式保存到父组件状态的目标。
核心思路
我们需要让每个输入框携带两个关键信息:对应的星期(比如monday)和时间类型(startTime/endTime),然后在父组件的onChange函数里解析这些信息,精准更新对应的状态字段。
步骤1:修复星期名称的映射
你的Table组件用了moment.weekdays(true)获取星期缩写(比如Mon),但父组件state的键是完整的小写星期名(monday),所以需要做一个映射转换:
在Table组件里添加一个星期映射表:
const dayAbbrToKey = { Mon: 'monday', Tue: 'tuesday', Wed: 'wednesday', Thu: 'thursday', Fri: 'friday', Sat: 'saturday', Sun: 'sunday' };
步骤2:修改Table组件的输入框
主要做这几个调整:
- 给每个input设置包含星期和时间类型的
name属性 - 用父组件传入的状态值替换硬编码的
defaultValue - 移除每个input外的冗余form(只需要在父层统一处理提交)
修改后的Table组件:
import React from 'react'; import moment from 'moment'; const dayAbbrToKey = { Mon: 'monday', Tue: 'tuesday', Wed: 'wednesday', Thu: 'thursday', Fri: 'friday', Sat: 'saturday', Sun: 'sunday' }; export default class Table extends React.Component { constructor(props) { super(props); this.state = { weekDays: moment.weekdays(true) }; } render() { const { edit, onChange, weekTimes } = this.props; return ( <table style={{ textAlign: "center" }}> <thead> <tr> <td style={{ opacity: 0 }} /> {this.state.weekDays.map(day => ( <td key={day}> <p>{day}</p> </td> ))} </tr> </thead> <tbody> <tr> <td> <p>Opening:</p> </td> {this.state.weekDays.map((dayAbbr, index) => { const dayKey = dayAbbrToKey[dayAbbr]; const currentTime = weekTimes[dayKey]?.startTime || ''; return ( <td key={`open-${index}`}> {edit ? ( <input onChange={onChange} name={`${dayKey}.startTime`} placeholder="open time" value={currentTime} type="time" // 推荐用time类型,输入更规范 /> ) : ( <p>{currentTime || '-'}</p> )} </td> ); })} </tr> <tr> <td> <p>Closing:</p> </td> {this.state.weekDays.map((dayAbbr, index) => { const dayKey = dayAbbrToKey[dayAbbr]; const currentTime = weekTimes[dayKey]?.endTime || ''; return ( <td key={`close-${index}`}> {edit ? ( <input onChange={onChange} name={`${dayKey}.endTime`} placeholder="close time" value={currentTime} type="time" /> ) : ( <p>{currentTime || '-'}</p> )} </td> ); })} </tr> </tbody> </table> ); } }
步骤3:修改父组件的handleInput函数
现在我们可以通过解析input的name属性(比如monday.startTime),精准更新对应的状态字段,注意要用函数式setState确保基于最新状态更新:
修改后的父组件:
import React from 'react'; import Table from './Table'; class App extends React.Component { constructor(props) { super(props); this.state = { editMode: false, friday: { endTime: "", startTime: "" }, monday: { endTime: "", startTime: "" }, thursday: { endTime: "", startTime: "" }, tuesday: { endTime: "", startTime: "" }, wednesday: { endTime: "", startTime: "" }, saturday: { endTime: "", startTime: "" }, sunday: { endTime: "", startTime: "" } }; } handleInput = e => { const { value, name } = e.target; // 拆分name属性,得到星期和时间类型 const [dayKey, timeType] = name.split('.'); // 函数式setState,确保更新基于最新状态 this.setState(prevState => ({ [dayKey]: { ...prevState[dayKey], // 保留原有字段,避免覆盖 [timeType]: value } }), () => console.log('Updated state:', this.state)); }; handleFormSubmit = e => { e.preventDefault(); // 这里可以做提交逻辑,比如把this.state传给后端 console.log('Submitting times:', this.state); this.setState({ editMode: false }); }; render() { return ( <div className="App"> {/* 把所有星期时间状态传给Table组件 */} <Table edit={this.state.editMode} onChange={this.handleInput} weekTimes={{ friday: this.state.friday, monday: this.state.monday, thursday: this.state.thursday, tuesday: this.state.tuesday, wednesday: this.state.wednesday, saturday: this.state.saturday, sunday: this.state.sunday }} /> <div> {!this.state.editMode ? ( <button onClick={() => this.setState({ editMode: true })}> Edit </button> ) : ( <div> <button onClick={() => this.setState({ editMode: false })}> Cancel </button> <button onClick={this.handleFormSubmit}>Save</button> </div> )} </div> </div> ); } } export default App;
关键细节解释
- name属性的妙用:通过
${dayKey}.${timeType}的格式,我们可以在onChange里轻松解析出要更新的状态路径,这是React处理复杂表单的常用技巧。 - 函数式setState:当更新依赖于之前的状态时,必须用函数式setState,避免因为React状态更新的异步性导致错误。
- 扩展运算符保留原有字段:
...prevState[dayKey]确保我们只更新需要修改的时间字段,不会把另一个时间字段(比如endTime)清空。
备选方案:多个处理函数(不推荐)
如果确实需要用多个处理函数(虽然没必要,会增加代码冗余),可以这样实现:
- 父组件创建两个函数:
handleStartTimeChange和handleEndTimeChange,每个函数接收dayKey和value作为参数。 - Table组件里的每个输入框调用对应的函数,并传入当前的dayKey。
示例代码片段:
// 父组件的处理函数 handleStartTimeChange = (dayKey, value) => { this.setState(prevState => ({ [dayKey]: { ...prevState[dayKey], startTime: value } })); }; handleEndTimeChange = (dayKey, value) => { this.setState(prevState => ({ [dayKey]: { ...prevState[dayKey], endTime: value } })); }; // Table组件里的输入框 <input onChange={(e) => this.props.handleStartTimeChange(dayKey, e.target.value)} placeholder="open time" value={currentTime} />
不过显然单个onChange函数的方案更简洁易维护。
内容的提问来源于stack exchange,提问作者RCohen
相关产品推荐
相关产品推荐

