react the function of key and useEffect

29 views Asked by At
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

0

There are 0 answers