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

React Next.js实现Card组件单选切换className问题求助

解决方案:状态提升实现单选Card

你的问题核心是每个Card独立维护选中状态,导致跨组件状态无法同步。要实现同一时间仅一个Card选中,需要把选中状态从Card组件提升到父组件UserBookingData,由父组件统一控制所有Card的选中状态。

步骤1:修改父组件UserBookingData

在父组件中维护当前选中的booking唯一标识(这里用booking.ref),并给每个Card传递选中状态和点击回调:

const UserBookingData = ({ bookings }: any) => {  
    // 父组件统一管理选中的booking ref
    const [selectedBookingRef, setSelectedBookingRef] = useState<string | null>(null);

    const handleCardSelect = (ref: string) => {
        // 更新选中状态
        setSelectedBookingRef(ref);
        // 同步更新上下文状态
        zusContext.setState({
            bookingRef: ref,
            bookingLoaded: true
        });
    };

    return (
        <div className="col-span-6 py-2">
            {bookings?.map((booking: any) => (
                <Card 
                    key={booking.ref} {/* 用booking唯一标识做key,避免不必要的重渲染 */}
                    booking={booking}
                    // 每个Card根据自身ref判断是否选中
                    selected={selectedBookingRef === booking.ref}
                    // 点击时触发父组件的选中逻辑
                    onSelect={() => handleCardSelect(booking.ref)}
                />
            ))}
        </div>
    )
}

步骤2:修改Card组件

移除Card内部的selected局部状态,改用父组件传递的selected属性和onSelect回调:

const Card = ({ booking, selected, onSelect } : any) => {
    const bookingDate = moment(booking?.startAt);
    
    return (
        <div 
            onClick={onSelect} 
            className={`my-1 py-3 px-3 flex items-center rounded-lg ${
                selected 
                    ? 'cursor-default bg-white-dark' 
                    : 'bg-white group hover:bg-white-dark cursor-pointer'
            }`}
        >
            <div><svg className="w-14 fill-current text-white-dark4" viewBox="0 0 150 150"><path d="M 75, 75 m -75, 0 a 75,75 0 1,0 150,0 a 75,75 0 1,0 -150,0"/></svg></div>
            <div className="flex items-center justify-between w-full">
                <div className={`ml-3 ${selected ? '' : 'flex flex-col'}`}>
                    <div className="flex">
                        <div className={`text-blue text-xs px-2 py-[3px] rounded-md ${
                            selected ? 'bg-white' : 'bg-blue-light group-hover:bg-white' 
                        }`}>
                            {bookingDate.utc().format('DD MMM YYYY')}
                        </div>
                    </div>
                    <div className='truncate text-sm font-medium pt-1 max-w-[160px]'>{booking?.space?.title}</div>
                    <div className="text-sm text-dark text-[13px]">{booking?.space?.host?.firstname}</div>
                </div>
                <div><svg className="ml-3 mr-1 w-2 fill-current text-blue" viewBox="0 0 150 150"><path d="M 75, 75 m -75, 0 a 75,75 0 1,0 150,0 a 75,75 0 1,0 -150,0"/></svg></div>
            </div>
        </div>
    )
}

原理说明

  • 状态提升后,父组件的selectedBookingRef是所有Card的唯一数据源,任何Card点击都会更新这个状态,触发所有Card重新渲染。
  • 每个Card通过对比自身booking.ref和父组件的selectedBookingRef,动态切换className,确保同一时间只有一个Card处于选中状态。
  • 替换nanoid()生成的key为booking.ref,避免组件不必要的重挂载,提升性能。

内容的提问来源于stack exchange,提问作者Kevin Ganem

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 22:10:48