React中多组Yes/No按钮的状态管理优化方案咨询
优化多组Yes/No选项的React组件代码
问题背景
我开发了一个包含多组Yes/No选项的React组件,需求为:点击Yes按钮时该按钮背景变为绿色、No按钮变为红色;点击No按钮时该按钮背景变为绿色、Yes按钮变为红色。但目前为每组按钮单独创建了state,这并非最佳实践,希望得到更优的处理方式。
原代码
import React, { useState } from "react"; import "./Medicine.css"; const Medicine = () => { const [selectedButton, setSelectedButton] = useState(""); const [selectedButton1, setSelectedButton1] = useState(""); const [selectedButton2, setSelectedButton2] = useState(""); const [selectedButton3, setSelectedButton3] = useState(""); const [selectedButton4, setSelectedButton4] = useState(""); const [selectedButton5, setSelectedButton5] = useState(""); return ( <> <h1>Medicine</h1> <div className="parent_div"> <div className="child_div"> <p>page2</p> <div className="grand_div"> <div className="fcontainer"> <div className="fitem"> Did You come into the pharmacy today for Medicine? </div> <div className="fitem"> <button className={ selectedButton !== "" ? selectedButton === "no" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton("no")} > No </button> <button className={ selectedButton !== "" ? selectedButton === "yes" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton("yes")} > Yes </button> </div> </div> <hr /> <div> <h5>Where do you asked any of the following:</h5> <div style={{ marginTop: "10px" }}> <div className="fcontainer"> <div className="fitem ques">Who is the Medicine for?</div> <div className="fitem "> <button className={ selectedButton1 !== "" ? selectedButton1 === "no" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton1("no")} > No </button> <button className={ selectedButton1 !== "" ? selectedButton1 === "yes" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton1("yes")} > Yes </button> </div> </div> <div className="fcontainer"> <div className="fitem ques">What are yours symptoms?</div> <div className="fitem"> <button className={ selectedButton2 !== "" ? selectedButton2 === "no" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton2("no")} > No </button> <button className={ selectedButton2 !== "" ? selectedButton2 === "yes" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton2("yes")} > Yes </button> </div> </div> <div className="fcontainer"> <div className="fitem ques"> How long you had the symptoms? </div> <div className="fitem"> <button className={ selectedButton3 !== "" ? selectedButton3 === "no" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton3("no")} > No </button> <button className={ selectedButton3 !== "" ? selectedButton3 === "yes" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton3("yes")} > Yes </button> </div> </div> <div className="fcontainer"> <div className="fitem ques"> What action have you already taken? </div> <div className="fitem"> <button className={ selectedButton4 !== "" ? selectedButton4 === "no" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton4("no")} > No </button> <button className={ selectedButton4 !== "" ? selectedButton4 === "yes" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton4("yes")} > Yes </button> </div> </div> <div className="fcontainer"> <div className="fitem ques"> Are you taking any other medication? </div> <div className="fitem"> <button className={ selectedButton5 !== "" ? selectedButton5 === "no" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton5("no")} > No </button> <button className={ selectedButton5 !== "" ? selectedButton5 === "yes" ? "butn greenbtn" : "butn redbtn" : "butn" } onClick={() => setSelectedButton5("yes")} > Yes </button> </div> </div> </div> </div> </div> </div> </div> </> ); }; export default Medicine;
优化方案
1. 合并状态管理
将多个独立的useState合并为一个对象状态,用问题标识作为键,选中值作为值,简化状态维护。
2. 提取复用组件
创建YesNoButtonGroup组件,封装按钮的样式逻辑和点击事件,避免重复代码。
3. 数据驱动渲染
把所有问题整理成数组,通过遍历数组生成对应的选项组,新增问题只需修改数据数组即可。
优化后的完整代码
第一步:创建复用的按钮组件
// YesNoButtonGroup.js import React from "react"; const YesNoButtonGroup = ({ questionId, selectedValue, onSelect }) => { const getButtonClass = (buttonType) => { if (!selectedValue) return "butn"; return selectedValue === buttonType ? "butn greenbtn" : "butn redbtn"; }; return ( <div className="fitem"> <button className={getButtonClass("no")} onClick={() => onSelect(questionId, "no")} > No </button> <button className={getButtonClass("yes")} onClick={() => onSelect(questionId, "yes")} > Yes </button> </div> ); }; export default YesNoButtonGroup;
第二步:重构Medicine组件
import React, { useState } from "react"; import "./Medicine.css"; import YesNoButtonGroup from "./YesNoButtonGroup"; const Medicine = () => { // 用单个对象管理所有选项的选中状态 const [selectedAnswers, setSelectedAnswers] = useState({}); // 统一的选择处理函数 const handleSelect = (questionId, value) => { setSelectedAnswers(prev => ({ ...prev, [questionId]: value })); }; // 定义所有问题数据 const mainQuestion = { id: "main", text: "Did You come into the pharmacy today for Medicine?" }; const subQuestions = [ { id: "forWho", text: "Who is the Medicine for?" }, { id: "symptoms", text: "What are your symptoms?" }, { id: "symptomDuration", text: "How long have you had the symptoms?" }, { id: "takenAction", text: "What action have you already taken?" }, { id: "otherMedication", text: "Are you taking any other medication?" } ]; return ( <> <h1>Medicine</h1> <div className="parent_div"> <div className="child_div"> <p>page2</p> <div className="grand_div"> {/* 主问题 */} <div className="fcontainer"> <div className="fitem">{mainQuestion.text}</div> <YesNoButtonGroup questionId={mainQuestion.id} selectedValue={selectedAnswers[mainQuestion.id]} onSelect={handleSelect} /> </div> <hr /> <div> <h5>Were you asked any of the following:</h5> <div style={{ marginTop: "10px" }}> {/* 子问题列表,通过循环渲染 */} {subQuestions.map(question => ( <div key={question.id} className="fcontainer"> <div className="fitem ques">{question.text}</div> <YesNoButtonGroup questionId={question.id} selectedValue={selectedAnswers[question.id]} onSelect={handleSelect} /> </div> ))} </div> </div> </div> </div> </div> </> ); }; export default Medicine;
优化说明
- 状态管理更高效:单个对象状态替代多个独立state,便于统一维护和后续扩展(比如批量获取所有答案)。
- 代码复用性提升:
YesNoButtonGroup组件封装了按钮的样式逻辑和交互逻辑,避免了大量重复的JSX和样式判断代码。 - 数据驱动更灵活:问题数据抽离成数组后,新增或修改问题只需调整数据数组,无需修改渲染逻辑,降低维护成本。
内容的提问来源于stack exchange,提问作者Abdul Rehman
相关产品推荐
相关产品推荐

