React Quiz App开发技术问询:如何实现仅被点击的按钮变色
解决React Quiz App中点击按钮全部变色的问题
嘿,很高兴看到你第一次React项目就做Quiz App!咱们来解决这个点击按钮全部变色的问题——根源其实很简单:你现在用了一个全局的color状态,所有的Quiz组件都共享这个状态,所以不管点哪个按钮,所有按钮都会跟着变颜色。
下面给你两种可行的解决方案,你可以根据自己的需求选一种:
方案一:让每个Quiz组件独立管理选中状态
这种方法最简单直接,每个Quiz组件自己维护自身的选中选项ID,各个题目之间互不干扰。
修改Quiz.js
import blob1 from './blob1.png' import blob2 from './blob2.png' import { useState } from 'react' // 引入useState export default function Quiz(props) { // 每个Quiz组件单独存储选中的选项ID,初始为null表示未选中 const [selectedId, setSelectedId] = useState(null) // 根据按钮ID是否匹配选中ID,动态生成样式 const getButtonStyle = (id) => ({ backgroundColor: selectedId === id ? '#D6DBF5' : '#F5F7FB', border: selectedId === id ? '1px solid #293264' : '1px solid black' }) return ( <div className='quiz-body'> <img src={blob1} className="blob1"/> <img src={blob2} className="blob2"/> <h2 className='h2-quiz'>{props.question}</h2> {/* 遍历选项数组渲染按钮,替代原来写死的四个按钮 */} {props.answerOptions.map(option => ( <button key={option.id} // 必须加key,React列表渲染的要求 className='btn-ans' onClick={() => setSelectedId(option.id)} style={getButtonStyle(option.id)} > {option.answerText} </button> ))} <br/> <br/> <hr/> </div> ) }
修改App.js中的渲染逻辑
把原来单独传递answer1-4的方式改成直接传递整个answerOptions数组:
const quizQ = qanda.map(ques => <Quiz key={ques.question} // 给每个Quiz组件加唯一key question={ques.question} answerOptions={ques.answerOptions} // 直接传递选项数组 /> )
同时你可以删掉App.js里的color状态和switchColor函数了,因为每个Quiz现在自己管理选中状态。
方案二:在父组件(App)统一管理所有选中状态
如果之后需要实现提交答案、计算得分的功能,这种方法更合适——所有选中状态都存在父组件中,方便后续统一处理。
修改App.js
import Main from './Main' import Quiz from './Quiz' import { useState } from 'react' export default function App() { const [switch1, setSwitch1] = useState(false) // 用对象存储每个题目对应的选中选项ID,键用题目内容作为唯一标识 const [selectedAnswers, setSelectedAnswers] = useState({}) const qanda = [ // 你的题目数据保持不变 ] // 更新选中答案的函数:接收题目标识和选项ID const handleSelectAnswer = (question, optionId) => { setSelectedAnswers(prev => ({ ...prev, [question]: optionId // 更新对应题目的选中ID })) } const quizQ = qanda.map(ques => <Quiz key={ques.question} question={ques.question} answerOptions={ques.answerOptions} selectedId={selectedAnswers[ques.question]} // 把当前题目的选中ID传给Quiz onSelect={(optionId) => handleSelectAnswer(ques.question, optionId)} // 传递选择回调 /> ) function switchIt() { setSwitch1(prevValue => !prevValue) } return ( <div className="body"> {switch1 ? quizQ : <Main onclick={switchIt}/> } </div> ) }
修改Quiz.js
import blob1 from './blob1.png' import blob2 from './blob2.png' export default function Quiz(props) { const getButtonStyle = (id) => ({ backgroundColor: props.selectedId === id ? '#D6DBF5' : '#F5F7FB', border: props.selectedId === id ? '1px solid #293264' : '1px solid black' }) return ( <div className='quiz-body'> <img src={blob1} className="blob1"/> <img src={blob2} className="blob2"/> <h2 className='h2-quiz'>{props.question}</h2> {props.answerOptions.map(option => ( <button key={option.id} className='btn-ans' onClick={() => props.onSelect(option.id)} style={getButtonStyle(option.id)} > {option.answerText} </button> ))} <br/> <br/> <hr/> </div> ) }
额外小建议
- 列表渲染时一定要加
key属性,这是React的最佳实践,能避免不必要的渲染错误。 - 不要单独传递
answer1、answer2这类props,直接传递整个选项数组然后遍历渲染,代码会更灵活,以后选项数量变化也不用修改组件结构。
加油,你的第一个React项目已经做得很棒了,继续坚持下去!
内容的提问来源于stack exchange,提问作者PawAMeditateguy
相关产品推荐
相关产品推荐

