如何实现点击单个手风琴组件时,阻止其他手风琴组件展开?
解决手风琴组件互斥展开问题
你的问题根源在于每个AccordionItemFAQ组件各自维护独立的isOpen状态,它们之间无法同步状态,所以做不到点击一个时关闭其他。正确的做法是把状态提升到父组件(FAQ页面)统一管理,通过控制当前展开的FAQ ID来实现互斥效果。
第一步:修改AccordionItemFAQ组件
移除组件内部的isOpen状态,改为通过props接收外部传入的展开状态和点击事件:
import { memo } from "react"; import styles from "./AccordionItemFAQ.module.scss"; interface AccordionItemFAQProps { title: string; content: string; isOpen: boolean; onClick: () => void; } const AccordionItemFAQ: React.FC<AccordionItemFAQProps> = ({ title, content, isOpen, onClick }) => { return ( <div className={styles.containerAll}> <button onClick={onClick} className={styles.containerTitle}> {title} </button> {isOpen && ( <div className={styles.containerContent}> <div className={styles.splitter}></div> <div className={styles.content}>{content}</div> </div> )} </div> ); }; export default memo(AccordionItemFAQ);
第二步:修改FAQ父组件
在父组件中添加状态管理当前展开的FAQ ID,渲染每个AccordionItemFAQ时传入对应的展开状态和点击回调:
import styles from "styles/pages/FAQ.module.scss"; import type { LayoutProps } from "@root/layouts"; import { buildMainLayout } from "@root/layouts"; import { useEffect, useState } from "react"; import { FaqTable } from "@root/constants/types"; import axios from "axios"; import AccordionItemFAQ from "@root/components/AccordionItemFAQ"; export default function Faq() { const [faqTable, setFaqTable] = useState<FaqTable[]>([]); const [openFaqId, setOpenFaqId] = useState<number | null>(null); // 记录当前展开的FAQ ID const api = "http://localhost:8088/api/v1/faq"; const loadFaqTable = () => { axios.get(api).then((response) => setFaqTable(response.data)); }; useEffect(() => { loadFaqTable(); }, []); const handleAccordionClick = (faqId: number) => { // 如果点击的是已经展开的,就关闭;否则展开当前的 setOpenFaqId(openFaqId === faqId ? null : faqId); }; return ( <div> <h1>FAQ</h1> <div className={styles.parentContainer}> {faqTable.map((item) => ( <AccordionItemFAQ key={item.faqId} title={item.question} content={item.answer} isOpen={openFaqId === item.faqId} onClick={() => handleAccordionClick(item.faqId)} ></AccordionItemFAQ> ))} </div> </div> ); } // <-- layout const layoutProps: LayoutProps = { mainClassName: "faq", currentPageDescription: "faqPage", }; Faq.layout = buildMainLayout(layoutProps);
原理说明
- 父组件通过
openFaqId状态唯一标记当前展开的FAQ项,所有子组件的展开状态都由这个值决定 - 点击某个手风琴项时,父组件更新
openFaqId:如果是当前展开的项,则置为null(关闭);否则设为该项的ID(展开该项,同时自动关闭其他项) - 这种状态提升的方式是React中处理组件间状态联动的标准方案,避免了子组件状态孤立的问题
内容的提问来源于stack exchange,提问作者denns9491
相关产品推荐
相关产品推荐

