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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 23:44:57