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

Next.js 14中useState不生效?自定义Select组件状态异常

自定义Select组件useState不更新的解决方案

核心问题分析与修复

1. Select.Option未绑定点击事件

你的SelectOption组件没有将接收的props(包括onClick)传递给内部DOM元素,导致点击选项时handleSelect函数完全不会触发——这是状态不更新的根本原因。

修改SelectOption组件,把props传递给内部div:

import { OptionProps } from '@/components/global-types';
import { twMerge } from 'tailwind-merge';

export default function SelectOption({ children, className, ...props }: OptionProps) {
  return (
    <div 
      className={twMerge('flex items-center justify-between cursor-pointer hover:bg-zinc-700 text-white h-8 px-2 whitespace-nowrap rounded', className)}
      {...props} // 关键:传递所有props,包括onClick
    >
      {children}
    </div>
  );
}

2. 点击选项后下拉框未可靠关闭(优化项)

当前点击选项后,事件会冒泡到SelectRoot的div,触发开关状态反转,但这种方式依赖事件冒泡,逻辑不够清晰。可以主动控制下拉框关闭:

第一步:修改SelectRoot组件,添加开关回调

'use client';
import { SelectProps } from '@/components/global-types';
import { ChevronDown, ChevronUp } from 'lucide-react';
import { useState } from 'react';
import { twMerge } from 'tailwind-merge';

export default function SelectRoot({ className, children, selected, onToggle, ...props }: SelectProps & { onToggle?: (open: boolean) => void }) {
  const [open, setOpen] = useState(false);

  const handleToggle = () => {
    const newState = !open;
    setOpen(newState);
    onToggle?.(newState);
  };

  return (
    <div
      className={twMerge('group rounded relative cursor-pointer h-8 m-5 px-2 flex items-center flex-row-reverse justify-between bg-white', className)}
      onClick={handleToggle}
      {...props}
    >
      {open ? <ChevronUp className="group-hover:opacity-70" /> : <ChevronDown className="group-hover:opacity-70" />}
      {selected}
      {open && children}
    </div>
  );
}

第二步:在Ferramentas组件中主动控制关闭

'use client';
import Image from 'next/image';
import { Select } from '@/components/ui/select';
import { ferramentas } from '@/libs/ferramentas';
import { useState } from 'react';
import { Check } from 'lucide-react';

export default function Ferramentas() {
  const [tool, setTool] = useState('');
  const [selectOpen, setSelectOpen] = useState(false);

  const handleSelect = (option: string) => {
    setTool(option);
    setSelectOpen(false); // 选中后直接关闭下拉框
  };

  // 优化:显示选中工具的名称而非ID
  const selectedTool = ferramentas.find(f => f.item_id === tool);

  return (
    <div className="ml-16">
      <Select.Root 
        className="w-[500px]" 
        selected={selectedTool?.name || '请选择工具'} 
        onToggle={setSelectOpen}
      >
        <Select.Content>
          {ferramentas.map((ferramenta) => (
            <Select.Option key={ferramenta.item_id} onClick={() => handleSelect(ferramenta.item_id)}>
              <div className="flex items-center gap-3">
                <Image alt={ferramenta.name} src={`https://render.albiononline.com/v1/item/${ferramenta.item_id}.png`} width={32} height={32} />
                {ferramenta.name}
              </div>
              {tool === ferramenta.item_id ? <Check /> : null}
            </Select.Option>
          ))}
        </Select.Content>
      </Select.Root>
      <h1>{selectedTool?.name || tool}</h1>
    </div>
  );
}

额外说明

  • 修复第一个问题后,点击选项时handleSelect会正常触发,tool状态也会更新;
  • 第二个优化项是为了让下拉框的关闭逻辑更可控,避免冒泡带来的意外问题;
  • 最后添加的显示名称逻辑是提升用户体验的小改进,可根据需求调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 15:54:57