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

React中点击自定义Select组件触发表单required验证异常求助

解决点击自定义SelectBox触发表单必填验证的问题

问题原因

  1. 按钮默认类型触发表单提交:SelectBox组件中用于展开下拉的按钮未指定type="button",HTML里按钮默认类型为submit,点击时会触发表单提交逻辑,进而触发必填字段的验证提示。
  2. 多余的onChange绑定:SelectBox最外层的<div>绑定了onChange事件,属于不必要的冗余绑定,会造成额外的事件触发干扰。

解决方案

1. 修正SelectBox触发按钮的类型

在SelectBox组件的展开按钮上明确添加type="button",避免触发表单提交:

// SelectBox组件内的触发按钮修改
<button type="button" onClick={openDropDown}>
  {selectedValue === undefined || selectedValue === '' ? placeHolder : selectedValue}
</button>

2. 移除SelectBox外层div的冗余onChange绑定

删除SelectBox组件最外层div上的onChange属性,该元素无需监听change事件:

// 原代码
<div onChange={onChange} ref={selectRef}>

// 修改后
<div ref={selectRef}>

3. 修正主文件的表单嵌套结构(推荐)

主文件中表单的DOM嵌套存在错误,修正后确保表单标签正确包裹所有表单控件:

// 主文件表单部分修改
<form>
  <div id="content-div">
    <label htmlFor="nameid">Name</label>
    <TextField 
      required 
      onChange={SavingDetails} 
      value={userDetails.username} 
      id="nameid" 
      name="username" 
      type="text" 
    />
  </div>

  <div id="content-div">
    <label htmlFor="num">Phone</label>
    <TextField 
      required 
      onChange={SavingDetails} 
      value={userDetails.userphone} 
      id="num" 
      name="userphone" 
      type="phone" 
    />
  </div>
</form>

<SelectBox 
  onChange={SavingDetails} 
  selectBoxWidth="80%" 
  placeHolder="Choose"
>
  <MenuItem value="None">None</MenuItem>
  {menuItems.map((val, ind) => (
    <MenuItem value={val} key={ind}>{val}</MenuItem>
  ))}
</SelectBox>

完整修改后的SelectBox组件代码

import { useState, useRef, useEffect, Children, cloneElement, useCallback } from "react";

export function MenuItem({ value, children, onSelect, isSelected }) {
    return (
        <button
            type="button"
            value={value}
            onClick={() => onSelect(value)}
            className={isSelected ? 'active-dd-btn' : ''}
        >
            {children}
        </button>
    );
}

export function SelectBox({ placeHolder = 'Placeholder..', children, onChange }) {
    const selectRef = useRef(null);
    const [isOpen, setOpen] = useState(false);
    const [selectedValue, setSelectedValue] = useState("");

    const HandleChange = useCallback(
        (value) => {
            onChange(value);
            setSelectedValue(value);
            setOpen(false);
        },
        [onChange]
    );

    function openDropDown() {
        setOpen(!isOpen);
    }

    useEffect(() => {
        const handleClickAway = (event) => {
            if (selectRef.current && !selectRef.current.contains(event.target)) {
                setOpen(false);
            }
        };

        document.addEventListener("mousedown", handleClickAway);

        return () => {
            document.removeEventListener("mousedown", handleClickAway);
        };
    }, []);

    return (
        <div ref={selectRef}>
            <button type="button" onClick={openDropDown}>
                {selectedValue === undefined || selectedValue === '' ? placeHolder : selectedValue}
            </button>
            {isOpen && (
                <div id="dropdown">
                    {Children.map(children, (child) =>
                        cloneElement(child, {
                            onSelect: HandleChange,
                            isSelected: child.props.value === selectedValue
                        })
                    )}
                </div>
            )}
        </div>
    );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:53:18