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

React实现日期选择默认结束日期同步开始日期且禁止早于开始日期

React 日期选择逻辑实现方案

直接基于现有代码做最小改动即可满足需求,核心修改逻辑如下:

  • 监听开始日期变更事件,选中开始日期时自动给结束日期赋相同默认值,不限制后续用户手动修改结束日期
  • 做双层日期合法性校验:原生日期选择器层面限制可选范围,JS逻辑层面拦截非法输入,同时增加错误提示和提交拦截

具体修改步骤

  1. 新增错误提示状态,存放日期校验的报错信息
    在原有state声明区域加一行代码:
    const [dateError, setDateError] = useState("");
    
  2. 修改开始日期的输入处理逻辑,实现默认值自动填充
    把textChange函数里case "start"的分支替换为以下代码:
    case "start":
      const newStartVal = e.target.value;
      setStart(newStartVal);
      // 自动同步结束日期默认值,用户后续可手动修改
      setEnd(newStartVal);
      // 清空历史校验错误
      setDateError("");
      break;
    
  3. 修改结束日期的输入处理逻辑,加入合法性拦截
    把textChange函数里case "end"的分支替换为以下代码:
    case "end":
      const newEndVal = e.target.value;
      // 拦截早于开始日期的非法输入
      if (start && newEndVal < start) {
        setDateError("结束日期不能早于开始日期");
        return;
      }
      setDateError("");
      setEnd(newEndVal);
      break;
    
  4. 给结束日期输入框加原生可选范围限制,从交互层面避免用户选到非法日期
    给id为end的date类型input加min={start}属性,修改后标签代码如下:
    <input
      type="date"
      name="end"
      value={end}
      onChange={textChange}
      id="end"
      min={start}
    />
    
  5. 增加错误提示展示,同时给提交按钮加禁用逻辑,避免非法值提交
    在结束日期输入框的父级label下方加错误提示渲染:
    {dateError && <p style={{ color: "red", fontSize: "14px", margin: "4px 0" }}>* {dateError}</p>}
    
    给Next按钮加disabled属性,存在错误或者日期未填时禁止点击:
    <button
      disabled={!!dateError || !start || !end}
      onClick={() =>
        next({           
          // 保留原有其他传参
          start,
          end
        })
      }
    >
      Next
    </button>
    

注:原有代码里textChange函数有两处重复的e?.target?.id === undefined判断,会导致selChoice2永远无法被赋值,属于原有逻辑bug,建议根据下拉组件的传值特征调整判断条件,比如给两个CustomDropdown单独写onChange回调,不要和表单输入共用textChange处理函数。另外JSX里label的for属性需要写成htmlFor,否则会有控制台警告。


修改后完整代码参考

export default function SelectionChoice({ next, selChoice2, setSelChoice2 }) {
  const [summary, setSummary] = useState("");
  const [start, setStart] = useState("");
  const [end, setEnd] = useState("");
  const [selChoice1, setSelChoice1] = useState();
  const [data, setData] = useState([])
  // 新增日期错误状态
  const [dateError, setDateError] = useState("");


  useEffect(() => {
    myApi.functionA()
      .then((res) => {
        console.log(res);
        setData(res.data.data);
      })
      .catch((err) => {
        console.log(err);
      });
  }, []);

  // ... 原有省略的业务逻辑
  const choice1 = data?.map((item) => {
    return {
      label: item.name,
      value: item.id
    };
  });

  const choice2 = data?.flatMap((item) => {
    return item.choice2.map((c) => ({
      label: c.name,
      value: c.id
    }));
  });

  const textChange = (e) => {
    // 建议单独给下拉组件写onChange,这里仅保留表单输入处理逻辑
    if (e?.target?.id === "summary") {
      setSummary(e.target.value);
      return;
    }
    switch (e.target.id) {    
      // ... 原有其他case分支
      case "start":
        const newStartVal = e.target.value;
        setStart(newStartVal);
        setEnd(newStartVal);
        setDateError("");
        break;
      case "end":
        const newEndVal = e.target.value;
        if (start && newEndVal < start) {
          setDateError("结束日期不能早于开始日期");
          return;
        }
        setDateError("");
        setEnd(newEndVal);
        break;
      default:
    }
  };
  return (
    <>
      <form>
        <div >
          Choose choice1 and choice2
        </div>
        <div>
          <label>
            Choice1:
            <CustomDropdown
              options={choice1}
              value={selChoice1}
              setValue={setSelChoice1}
              isMulti={true}
            />
          </label>
          <label>
            Choice2:
            <CustomDropdown
              options={choice2}
              value={selChoice2}
              setValue={setSelChoice2}
              isMulti={true}
            />
          </label>
        </div>
        <div>
          <label>
            Start:
            <div>
              <input
                type="date"
                name="start"
                value={start}
                onChange={textChange}
                id="start"
              />
            </div>
          </label>
          <label>
            End:
            <div>
              <input
                type="date"
                name="end"
                value={end}
                onChange={textChange}
                id="end"
                min={start}
              />
            </div>
          </label>
          {dateError && <p style={{ color: "red", fontSize: "14px", margin: "4px 0" }}>* {dateError}</p>}
          <p className="formfield">
            <label
              htmlFor="summary"
            >
              Description :
              <textarea
                value={summary}
                onChange={textChange}
                name="summary"
                id="summary"
                cols="10"
                rows="10"
              />
            </label>
          </p>
        </div>
      </form>
        <button
          disabled={!!dateError || !start || !end}
          onClick={() =>
            next({           
              // 原有其他传参保留
              start,
              end
            })
          }
        >
          Next
        </button>
    </>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 08:03:19