React下拉组件首次点击导入错误3D模型问题排查求助
React下拉组件首次点击选项模型导入错误的解决办法
你的问题核心出在handleOptionClick函数的逻辑里,原因是React的setState是异步操作:当你调用setSelectedOption(option)后,selectedOption并不会立刻更新,此时你用selectedOption?.name做判断,拿到的其实是上一次的选中值,这就导致前几次点击时逻辑判断混乱,触发了错误的模型导入。
修改方案
直接使用点击事件传入的option参数进行判断,同时更新数组时采用函数式更新,避免闭包导致的旧值问题:
const handleOptionClick = (option: Option) => { setSelectedOption(option); setIsOpen(false); // 直接用当前点击的option判断,而非异步更新后的state if (option.name === "m-st") { props.setID("m-st"); // 函数式更新,用prevState获取最新数组值 props.setSysmexArray(prev => [...prev, [props.xAxis, props.yAxis, props.zAxis]]); } if (option.name === "CR10") { props.setID("r-cr10"); props.setCr10_no_7thArray(prev => [...prev, [props.xAxis, props.yAxis, props.zAxis]]); } };
修改后的完整组件代码
import { useState, useEffect, useRef, Dispatch, SetStateAction, } from "react"; const useOnClickOutside = <T extends HTMLElement>( ref: React.RefObject<T>, handler: () => void ) => { useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (ref.current && !ref.current.contains(event.target as Node)) { handler(); } }; document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [ref, handler]); }; interface Option { name: string; value: string | number; image: string; id: string; } interface DropdownProps { options: Option[]; title: string; xAxis: number; yAxis: number; zAxis: number; SysmexArray: number[][]; setSysmexArray: Dispatch<SetStateAction<number[][]>>; cr10_no_7thArray: number[][]; setCr10_no_7thArray: Dispatch<SetStateAction<number[][]>>; ID: string; setID: Dispatch<SetStateAction<string>>; } const Dropdown: React.FC<DropdownProps> = (props) => { const [isOpen, setIsOpen] = useState(false); const [selectedOption, setSelectedOption] = useState<Option | undefined>( undefined ); const dropdownRef = useRef<HTMLDivElement>(null); const toggleDropdown = () => setIsOpen(!isOpen); useOnClickOutside(dropdownRef, () => setIsOpen(false)); useEffect(() => { const handleEscapeKeyPress = (event: KeyboardEvent) => { if (event.key === "Escape") { setIsOpen(false); } }; document.addEventListener("keydown", handleEscapeKeyPress); return () => { document.removeEventListener("keydown", handleEscapeKeyPress); }; }, []); const handleOptionClick = (option: Option) => { setSelectedOption(option); setIsOpen(false); if (option.name === "m-st") { props.setID("m-st"); props.setSysmexArray(prev => [...prev, [props.xAxis, props.yAxis, props.zAxis]]); } if (option.name === "CR10") { props.setID("r-cr10"); props.setCr10_no_7thArray(prev => [...prev, [props.xAxis, props.yAxis, props.zAxis]]); } }; return ( <div className="relative pl-0" ref={dropdownRef}> <button type="button" className="flex items-center justify-between w-full px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" onClick={toggleDropdown} > {selectedOption ? ( <> {props.title} {console.log(`${selectedOption.name} : ${selectedOption.value}`)} </> ) : ( props.title )} <svg className={`w-5 h-5 ml-2 transition-transform ${ isOpen ? "transform rotate-180" : "" }`} viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" > <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" /> </svg> </button> {isOpen && ( <div className="absolute z-10 w-full mt-2 bg-white rounded-md shadow-lg"> <ul className="py-1"> {props.options.map((option) => ( <li key={option.value} className="flex flex-col justify-center items-center px-4 py-2 text-sm text-gray-700 cursor-pointer hover:bg-gray-100" onClick={() => handleOptionClick(option)} > <img src={option.image} height={100} width={100} alt={option.name} />{" "} <div className="text-center">{option.name}</div> </li> ))} </ul> </div> )} </div> ); }; export default Dropdown;
额外说明
- 去掉了原代码中
setID的函数式写法,因为这里不需要依赖旧的ID值,直接赋值更简洁 - 数组更新采用
prev => [...prev, newItem]的方式,确保每次都基于最新的数组状态进行更新,避免闭包陷阱
内容的提问来源于stack exchange,提问作者naeemgg
相关产品推荐
相关产品推荐

