I'm creating a Quiz app in Reactjs,
The issue is When I try to select the one option it get selected but if I try to select the other one it also gets selected. I want if A is selected and if the user clicked on B the A will be unselected and B will get selected.
I'd tried to do it in the child component as well as the parent component. In Child, I'm able to select one div but if I click on the other option they are also getting selected. In Parent when I try to select any option it is selecting all of them.
Option.js (child component)
import React, { useState } from 'react'
function Option({ index, item, changeIndexValue }) {
const [currentOptionSelected, setCurrentOptionSelected] = useState(false)
const handleClick = (index) => {
changeIndexValue(index)
setCurrentOptionSelected(prevState => !prevState)
}
return (<>
<div className='option'
style={{ border: currentOptionSelected ? "2px solid red" : "1px solid black" }}
onClick={() => handleClick(index)}
key={index}
><p>{item}</p>
</div>
</>
)
}
export default Option
QuizMain.js (Parent component)
import React, { useState } from 'react'
import ProgressBar from '../ProgressBar/ProgressBar';
import './QuizMain.css'
import { useNavigate, useLocation } from 'react-router-dom';
import { useOutletContext } from "react-router-dom";
import ScoreCard from '../ScoreCard/ScoreCard';
import Option from '../Option/Option';
function QuizMain() {
const [currentQuestion, setCurrentQuestion] = useState(0)
const [changeCurrentQuestion, currentQuestionNumber, questionAre] = useOutletContext();
const [finalReport, setFinalReport] = useState([]);
const [finalReportVisible, setFinalReportVisible] = useState(false)
const [correctAnswer, setCorrectAnswer] = useState("")
const changeCorrectAnswer = (value) => {
setCorrectAnswer(value)
}
const [indexValue, setIndexValue] = useState("")
const changeIndexValue = (value) => {
setIndexValue(value)
}
const location = useLocation();
const { chooseQuizType } = location.state;
console.log(chooseQuizType, 'location')
const handleSubmit = () => {
const answersCurrentQuestion = questionAre[currentQuestionNumber].options.map((item) => item)
if (chooseQuizType == "withAnsers") {
console.log(answersCurrentQuestion[indexValue], 'selected option')
if (answersCurrentQuestion[indexValue] == questionAre[currentQuestionNumber].correctAnswer) {
alert('Correct answer')
} else {
alert('Wrong answer')
changeCorrectAnswer(questionAre[currentQuestionNumber].correctAnswer)
}
}
setFinalReport(prevState => [...prevState, {
question: questionAre[currentQuestionNumber].question,
correctAnswer: questionAre[currentQuestionNumber].correctAnswer,
yourAnswer: answersCurrentQuestion[indexValue]
}])
}
return (<>
{finalReportVisible ? <ScoreCard finalReport={finalReport} /> :
<div className='quizMain'>
<div className='quizMain__main'>
<div className='questions'>
<h3>{questionAre && questionAre[currentQuestionNumber]?.question}</h3>
</div>
<div className='options'>
{questionAre && questionAre[currentQuestionNumber]?.options.map((item, index) => {
return <Option
key={index}
item={item}
index={index}
changeCorrectAnswer={changeCorrectAnswer}
correctAnswer={correctAnswer}
indexValue={indexValue}
changeIndexValue={changeIndexValue}
/>
})}
<p>{correctAnswer}</p>
</div>
<div className='submit__button'>
<button onClick={handleSubmit}>Submit</button>
</div>
</div>
</div >
}
</>
)
}
export default QuizMain
In React, you should avoid putting too many logic in child components. Child components should be used to display information, let parent container handle logics.
In QuizMain.js (Parent), define a state to controll which option is currently selected
const [selected, setSelected] = useState(-1); // -1 means non is selected
also define a function which will be passed to Option component (Child) to update selection
const selectOption = (option) => {
setSelected(option);
}
In Option.js (Child), include the following to props
function Option({ index, item, onSelect, selected })
for the onClick callback of Option.js, just put onSelect(index) to it
onPress={ () => onSelect(index) }
Back to QuizMain.js, each Option component should be like
<Option
...
key={ index }
selected={ selected === index }
/>