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

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)清空。

备选方案:多个处理函数(不推荐)

如果确实需要用多个处理函数(虽然没必要,会增加代码冗余),可以这样实现:

  1. 父组件创建两个函数:handleStartTimeChange和handleEndTimeChange,每个函数接收dayKey和value作为参数。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:49:13