React实现点击展开容器时自动关闭其他容器的问题求助
实现折叠面板的互斥展开功能
我有一个接收props的容器组件,点击箭头按钮可以展开/收起内容。现在需要实现:打开某一个内容容器时,其他已打开的容器自动关闭。目前只能通过再次点击对应箭头按钮来关闭容器。
以下是我的子组件代码:
import { useState } from "react"; export default function Question(props) { const [clicked, setClicked] = useState(false); function clickedElement() { return setClicked(!clicked); } return ( <div className="question-cont"> <div className="question-cont-inner"> <h3>{props.head}</h3> <button onClick={() => clickedElement()}> {clicked ? ( <img src={props.img2} /> ) : ( <img src={props.img} /> )}{" "} </button> </div> {clicked ? <p>{props.description}</p> : ""} </div> ); }
父组件代码:
import Question from "../components/Question"; import questions from "../components/Questions"; export default function Sorular() { const questionList = questions.map((question) => { return ( <Question key={question.id} id={question.id} head={question.head} description={question.description} img={question.img} img2={question.img2} /> ); }); return ( <div className="sorular-container"> <div className="sorular-top"> <div className="sorular-top-back-img"> <a href="/"> <img src="./images/right-arrow-colorful.png" id="right-arrow-img" /> </a> </div> <div className="sorular-top-head"> <img src="./images/conversation.png" /> <h4>Sıkça Sorulan Sorular</h4> </div> </div> <div className="sorular-bottom">{questionList}</div> </div> ); }
解决方案:状态提升到父组件
当前每个Question组件各自维护自己的展开状态,导致组件间无法联动。要实现互斥展开,需要把当前展开的容器ID统一维护在父组件中,子组件根据父组件传递的状态判断是否展开。
修改父组件
在父组件中添加状态管理当前展开的ID,同时给子组件传递点击回调:
import { useState } from "react"; import Question from "../components/Question"; import questions from "../components/Questions"; export default function Sorular() { // 存储当前展开的问题ID,初始为null表示全部收起 const [expandedId, setExpandedId] = useState(null); // 处理点击事件:点击当前展开的ID则收起,否则切换到该ID const handleQuestionClick = (id) => { setExpandedId(expandedId === id ? null : id); }; const questionList = questions.map((question) => { return ( <Question key={question.id} id={question.id} head={question.head} description={question.description} img={question.img} img2={question.img2} // 传递是否展开的状态和点击回调 isExpanded={expandedId === question.id} onToggle={() => handleQuestionClick(question.id)} /> ); }); return ( <div className="sorular-container"> <div className="sorular-top"> <div className="sorular-top-back-img"> <a href="/"> <img src="./images/right-arrow-colorful.png" id="right-arrow-img" /> </a> </div> <div className="sorular-top-head"> <img src="./images/conversation.png" /> <h4>Sıkça Sorulan Sorular</h4> </div> </div> <div className="sorular-bottom">{questionList}</div> </div> ); }
修改子组件
移除子组件自身的状态,改用父组件传递的属性控制展开/收起:
export default function Question(props) { return ( <div className="question-cont"> <div className="question-cont-inner"> <h3>{props.head}</h3> <button onClick={props.onToggle}> {props.isExpanded ? ( <img src={props.img2} /> ) : ( <img src={props.img} /> )}{" "} </button> </div> {props.isExpanded ? <p>{props.description}</p> : ""} </div> ); }
原理说明
- 父组件统一管理所有折叠面板的展开状态,通过
expandedId记录当前唯一展开的容器ID; - 子组件不再维护自身状态,完全依赖父组件传递的
isExpanded判断是否展示内容; - 点击按钮时触发父组件的回调函数,更新
expandedId,从而实现点击一个面板时自动关闭其他面板的效果。
内容的提问来源于stack exchange,提问作者kehugnim
相关产品推荐
相关产品推荐

