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
相关产品推荐
相关产品推荐

