如何使用useState仅修改当前被点击的Accordion卡片样式
问题根源
你当前所有卡片共用同一个布尔类型的clicked状态,只要状态变更,所有卡片的样式判断条件都会同步更新,才会出现点击任意卡片全部变色的问题。
修复方案
根据业务需求分为两种实现场景:
场景1:每次仅允许一张卡片处于激活状态(常规手风琴效果)
将state改为存储当前激活卡片的唯一标识(建议用item的业务唯一id,无id可暂用map遍历的index代替),点击时仅更新当前标识的匹配状态即可。
代码示例:
// 初始值为null,代表无激活卡片 const [activeId, setActiveId] = useState(null); <div className="row"> {items && items.map((item, index) => ( {/* 必须给遍历项加唯一key,这里如果item有id优先用item.id */} <div className="col-md-6 faqpadding" key={item.id ?? index}> <Accordion className="cardHeight" style={{ backgroundColor: activeId === item.id ? "#fff" : "#0e2043", boxShadow: "0px 4px 22px 9px rgba(0, 0, 0, 0.17)", border: "1px solid #919191", color: activeId === item.id ? "#0e2043" : "#E3AB50", padding: "20px", }} > <AccordionSummary expandIcon={<ExpandMoreIcon />} {/* 动态修改无障碍属性,避免重复 */} aria-controls={`panel${item.id}-content`} id={`panel${item.id}-header`} onClick={() => { // 如果点击的是当前激活卡片,就取消激活,否则设为当前卡片id setActiveId(activeId === item.id ? null : item.id) }} > <Typography className={classes.heading} style={{ textAlign: "center" }} > {item.Title} </Typography> </AccordionSummary> <AccordionDetails> <Typography>{item.Content}</Typography> </AccordionDetails> </Accordion> </div> ))} </div>
场景2:允许多张卡片同时激活
将state改为存储对象格式的状态映射,key为卡片唯一标识,value为当前卡片的激活状态,点击时仅修改对应key的状态即可。
代码示例:
// 初始值为空对象,所有卡片默认未激活 const [activeMap, setActiveMap] = useState({}); <div className="row"> {items && items.map((item, index) => ( <div className="col-md-6 faqpadding" key={item.id ?? index}> <Accordion className="cardHeight" style={{ backgroundColor: activeMap[item.id] ? "#fff" : "#0e2043", boxShadow: "0px 4px 22px 9px rgba(0, 0, 0, 0.17)", border: "1px solid #919191", color: activeMap[item.id] ? "#0e2043" : "#E3AB50", padding: "20px", }} > <AccordionSummary expandIcon={<ExpandMoreIcon />} aria-controls={`panel${item.id}-content`} id={`panel${item.id}-header`} onClick={() => { setActiveMap(prev => ({ ...prev, [item.id]: !prev[item.id] })) }} > <Typography className={classes.heading} style={{ textAlign: "center" }} > {item.Title} </Typography> </AccordionSummary> <AccordionDetails> <Typography>{item.Content}</Typography> </AccordionDetails> </Accordion> </div> ))} </div>
注意事项
原来的代码中AccordionSummary的aria-controls和id属性为固定值,多卡片重复会导致无障碍属性冲突,上述代码中已改为和item唯一标识绑定的动态值。
内容的提问来源于stack exchange,提问作者Jay Modi
相关产品推荐
相关产品推荐

