Ok, to ten projekt roboczy, czyli quiz app w React. Pokazujemy, jak wygląda timer. Potem pewnie to usunę i zrobię tutorial od nowa, ale na razie musimy mieć działającą aplikację.

Ok, oto kod:

import { useState, useEffect } from 'react';

export default function Timer({ timeout, onTimeout, blocked}) {
  const [remainingTime, setRemainingTime] = useState(timeout);

  useEffect(() => {
    let timer;

    timer = setTimeout(onTimeout, timeout);

    return () => {
      clearTimeout(timer);
    };
  }, [timeout, onTimeout]);

  useEffect(() => {
    let interval;
    if(blocked === false){
        interval = setInterval(() => {
            setRemainingTime((prevRemainingTime) => prevRemainingTime - 100);
          }, 100);
    } else {
        clearInterval(interval);
    }
    
    return () => {
      clearInterval(interval);
    };
  }, [blocked]);

    return (
        <progress
          id="timer"
          max={timeout}
          value={remainingTime}
        />
      );
}

Czyli tak, odpalamy timeout na funkcję (ta funkcja to skip answer). Jednocześnie odpalamy interwał na usuwanie z progressu reszty czasu. Funkcje cleanup czyszczą timeout i interval.

Natomiast bajer polega na tym, że mamy prop o nazwie blocked. Ten prop jest od tego, że ktoś może dać selected answer w innym miejscu quizu i wtedy timer ma się zatrzymać.

Wtedy czekamy na pokazanie, czy odpowiedź jest dobra, a timer ma być zatrzymany.

Dokładnie to w App2 mamy taki stan:

const [timerBlocked, setTimerBlocked] = useState(false);

Ten stan idzie do timera jako mode:

{shouldRenderQuestion && usingTimer ?  
       <Timer 
       key={index+1} 
       timeout={5000} 
       onTimeout={timerBlocked ? null : skipQuestion} 
       blocked={timerBlocked}
      /> : null }

Key ma index + 1 bo już jeden taki klucz mamy użyty i nie działało poprawnie. Ok, to powinniśmy rozumieć, natomiast setTimerBlocked idzie do selectablelist:

{shouldRenderQuestion ? <SelectableList3 
      idx={index} 
      shuffle={true}
      key={index} 
      setTimerBlocked={setTimerBlocked}
      setNextQuestion={setNextQuestion } 
      skipQuestion={skipQuestion}
      showCorrect={true}/> : "Quiz Finished"}

Tam po wybraniu odpowiedzi mamy zablokowanie timera.