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

如何在React中正确管理Shadcn Toggle组件的单选状态?

问题分析与解决方法

你的问题根源在于Shadcn Toggle组件的onPressedChange事件会在组件pressed状态变化时触发(无论从false变true还是true变false),而你当前的处理逻辑是只要触发事件就直接设置对应状态,导致点击非默认Toggle时出现状态来回覆盖的情况:

  1. 点击目标Toggle时,它的pressed变为true,触发onPressedChange,状态被设置为对应类型
  2. 此时默认Toggle(stroke-none)的pressed从true变为false,触发它的onPressedChange,状态又被改回stroke-none
  3. 最终状态来回跳动,视觉上无法正确切换激活状态,日志也会先后输出两次不同的值

解决方法

修改onPressedChange的处理逻辑,仅当Toggle被激活(isPressed为true)时才更新状态,避免非激活状态变化时的无效状态更新。

修改后的代码

首先调整每个Toggle的onPressedChange回调:

type StrokeToggleType = "stroke-none" | "stroke-solid" | "stroke-dash-1" | "stroke-dash-2";

const [strokeToggle, setStrokeToggle] = useState<StrokeToggleType>("stroke-none");

const handleToggleChange = (type: StrokeToggleType) => {
    setStrokeToggle(type);
};

// 可优化:将选项配置为数组,减少重复代码
const strokeOptions = [
    { type: "stroke-none", icon: <AiOutlineStop className='w-[56px] h-[40px]' /> },
    { type: "stroke-solid", icon: <GoDash className='w-[56px] h-[40px]' /> },
    { type: "stroke-dash-1", icon: <CgBorderStyleDashed className='w-[56px] h-[40px]' /> },
    { type: "stroke-dash-2", icon: <AiOutlineSmallDash className='w-[56px] h-[40px]' /> },
];

return (
    <div className='flex justify-between'>
        {strokeOptions.map(option => (
            <Toggle
                key={option.type}
                aria-label={option.type}
                pressed={strokeToggle === option.type}
                // 仅在激活时更新状态
                onPressedChange={(isPressed) => isPressed && handleToggleChange(option.type)}
            >
                {option.icon}
            </Toggle>
        ))}
    </div>
);

原理说明

通过判断onPressedChange传递的isPressed参数,只在Toggle被用户点击激活(变为true)时才更新状态,而其他Toggle因状态变化变为非激活时,不会触发无效的状态重置,从而保证单选逻辑的正确性,视觉上也能正确显示当前激活的Toggle。

内容的提问来源于stack exchange,提问作者MInH THiỆn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 07:17:08