import { useState, useCallback, useRef } from 'react';
import QUESTIONS from '../questions.js';
import QuestionTimer from './QuestionTimer.jsx';
import quizCompleteImg from '../assets/quiz-complete.png';
import Answers from './Answers.jsx';
export default function Quiz() {
const [userAnswers, setUserAnswers] = useState([]);
const [answerState,setAnswerState] = useState('')
const activeQuestionIndex = userAnswers.length;
const quizIsComplete = activeQuestionIndex === QUESTIONS.length;
const selectedAnswerRef = useRef();
let time = 10000;
if(answerState === 'correct'||answerState==='wrong'){
time = 2000;
}else if(answerState==='answered'){
time = 1000;
}
const handleSelectAnswer = useCallback(function handleSelectAnswer(selectedAnswer) {
selectedAnswerRef.current = selectedAnswer;
if(selectedAnswer===null){
setAnswerState('');
setUserAnswers((prevUserAnswers) => {
return [...prevUserAnswers, ""];
});
}else{
setAnswerState('answered');
setTimeout(()=>{
if(selectedAnswer===QUESTIONS[activeQuestionIndex].answers[0]){
setAnswerState('correct');
}else{
setAnswerState('wrong');
}
setTimeout(()=>{
setAnswerState('');
setUserAnswers((prevUserAnswers) => {
return [...prevUserAnswers, selectedAnswer];
});
},2000);
},1000);
}
}, [activeQuestionIndex]);
const handleSkipAnswer = useCallback(() => handleSelectAnswer(null), [handleSelectAnswer]);
if (quizIsComplete) {
return (
<div id="summary">
<img src={quizCompleteImg} alt="Trophy icon" />
<h2>Quiz Completed!</h2>
</div>
);
}
return (
<div id="quiz">
<div id="question">
<QuestionTimer
key={time+activeQuestionIndex}
timeout={time}
onTimeout={handleSkipAnswer}
mode={answerState}
/>
<h2>{QUESTIONS[activeQuestionIndex].text}</h2>
<Answers
answers = {QUESTIONS[activeQuestionIndex].answers}
handleSelectAnswer = {handleSelectAnswer}
answerState = {answerState}
ref = {selectedAnswerRef} />
</div>
</div>
);
}
here is my Quiz component, the QuestionTimer component actually is a progressBar, and timeout is the max value of progressBar. i want the progressBar will update it's ui when i click one of the answers. Everytime i click answer, the state of Quiz will change cauesing Quiz's re-rendering. so the time will change along with state, so that the progressBar will update.
import { useState, useEffect } from 'react';
export default function QuestionTimer({ timeout, onTimeout, mode }) {
const [remainingTime, setRemainingTime] = useState(timeout);
useEffect(() => {
//console.log('SETTING TIMEOUT');
const timer = setTimeout(onTimeout, 10000);
return () => {
clearTimeout(timer);
};
}, [timeout]);
useEffect(() => {
console.log('SETTING INTERVAL');
const interval = setInterval(() => {
setRemainingTime((prevRemainingTime) => prevRemainingTime - 100);
}, 100);
return () => {
clearInterval(interval);
};
}, [timeout,onTimeout]);
return <progress id="question-time" max={timeout} value={remainingTime} className={mode}/>;
}
the code can work well now, However, when I don't use the 'key' attribute in the QuestionTimer component, the progress bar doesn't decrease but remains fixed at the maximum value. One argument is that when QuestionTimer re-renders, it doesn't trigger useEffect to execute again, causing setInterval to be called only once when the component mounts. However, even when I add 'timeout' to the second parameter of useEffect, why does useEffect still execute every time I click 'answer' and the time changes? Why does the progressBar's progress remain at 100% without changing?
i want to figure out why the progressBar remain fixed, rather than decrease along with time