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.