如何实现带SCSS样式的可用自定义Select组件?(附故障代码)
修复单选下拉选择器的功能问题
原代码核心问题
- 用布尔值
checked管理单选选中状态,和单选框的字符串值不匹配,导致状态混乱 - 未通过react-hook-form的
register正确绑定表单控件,无法收集表单数据 - 两个单选框同时设置
defaultChecked={checked},初始状态异常 - 单选框
onChange仅切换布尔值,未记录实际选中的选项值 - 选中选项后未自动收起下拉菜单
修复方案及完整代码
下面是修复后的Select.tsx,保持原有样式的同时解决功能问题:
import styles from "./select.module.scss"; import { useForm } from "react-hook-form"; import { useRef, useState, useEffect } from "react"; interface IFormInput { sortType: string; } const Select = () => { const { register, handleSubmit, watch } = useForm<IFormInput>({ defaultValues: { sortType: "Freelancer" } // 设置默认选中值 }); const [isOpened, setIsOpened] = useState(false); const selectedValue = watch("sortType"); // 实时监听选中值 const dropdownRef = useRef<HTMLSpanElement>(null); const onSubmit = (data: IFormInput) => { console.log(data); }; // 点击下拉区域外关闭菜单 useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setIsOpened(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); // 切换下拉展开状态 const toggleDropdown = () => { setIsOpened(!isOpened); }; // 选中选项后关闭下拉 const handleOptionSelect = () => { setIsOpened(false); }; return ( <div className={styles.select}> <p className={styles.pSelect}>Who are creating the ad?</p> <div className={styles.body}> <span ref={dropdownRef} className={`dropdown-el ${isOpened ? "expanded" : ""}`} > {/* 显示当前选中值,作为下拉触发按钮 */} <div onClick={toggleDropdown} className="selected-label"> {selectedValue} </div> <form onSubmit={handleSubmit(onSubmit)}> <div className="options"> <input type="radio" name="sortType" value="Freelancer" id="sort-relevance" {...register("sortType")} onChange={handleOptionSelect} /> <label htmlFor="sort-relevance">Freelancer</label> <input type="radio" name="sortType" value="Client" id="sort-best" {...register("sortType")} onChange={handleOptionSelect} /> <label htmlFor="sort-best">Client</label> </div> {/* 可选:添加提交按钮,或者通过其他方式触发提交 */} {/* <button type="submit">Submit</button> */} </form> </span> </div> </div> ); }; export default Select;
关键修复点说明
- 状态与表单绑定:用
watch("sortType")实时获取选中值,替代原有的布尔状态,同时通过{...register("sortType")}完成react-hook-form的控件注册 - 默认值设置:在
useForm中通过defaultValues设置初始选中值,避免手动处理defaultChecked的混乱 - 下拉交互优化:添加点击区域外关闭下拉的逻辑,选中选项后自动收起下拉,提升用户体验
- 触发区域优化:单独设置选中值显示区域作为下拉触发按钮,避免点击表单区域误触发展开/收起
样式适配提示
确保你的select.module.scss中包含以下类的样式(保持原样式逻辑即可):
.dropdown-el:下拉容器的基础样式.dropdown-el.expanded:下拉展开时的样式.selected-label:当前选中值的显示样式(可复用原标签样式).options:选项列表的容器样式
内容的提问来源于stack exchange,提问作者Artur Zuiev
相关产品推荐
相关产品推荐

