Обратный отсчет времени React
Я сделал таймер обратного отсчета.
const { useState,useEffect } = React;
const App = (props) => {
const hour = props.date.getHours();
const min = props.date.getMinutes();
const sec = props.date.getSeconds();
const [over, setOver] = useState(false);
const [[h, m, s], setTime] = useState([hour, min, sec]);
const tick =()=>{
if(over) return;
if (h === 0 && m === 0 && s === 0) {
setOver(true);
} else if (m === 0 && s === 0) {
setTime([h - 1, 59, 59]);
} else if (s == 0) {
setTime([h, m - 1, 59]);
} else {
setTime([h, m, s - 1]);
}
}
useEffect(()=>{
const timerID = setInterval(() => tick(), 1000);
return () => clearInterval(timerID);
})
return (
<p>{`${h.toString().padStart(2, '0')}:${m
.toString()
.padStart(2, '0')}:${s.toString().padStart(2, '0')}`}</p>
)
}
ReactDOM.render(<App date={new Date('Thu, 26 Sep 2022 22:00:00')}/>, document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Все работает хорошо. Но мне надо чтобы он показывал оставшееся время не от переданного в props. А от разницы между временем в props и текущем временем. Не могу понять как правильно передать разницу времени в компанент
Ответы (1 шт):
Наиболее подходящим на мой взгляд в React, использовать useEffect с отслеживанием tick и расчитывать разницу из миллисекунд. Передаем дату финиша, получаем оставшееся время, и экономим вызовы setState
Что касается дней, то наверно лучше показывать в зависимости от того сколько отрезков в 24 часа помещается, если меньше то смысла нет показывать.
Вариант 1
const { useState,useEffect } = React;
const App = ({date}) => {
const [finishTime] = useState(date.getTime());
const [[diffDays, diffH, diffM, diffS], setDiff] = useState([0, 0, 0, 0]);
const [tick, setTick] = useState(false);
useEffect(()=> {
const diff = (finishTime - new Date()) / 1000;
if (diff < 0) return // время вышло
setDiff([
Math.floor(diff / 86400), // дни
Math.floor((diff / 3600) % 24),
Math.floor((diff / 60) % 60),
Math.floor(diff % 60)
])
}, [tick, finishTime])
useEffect(()=>{
const timerID = setInterval(() => setTick(!tick), 1000);
return () => clearInterval(timerID);
}, [tick])
return (
<p>{`${diffDays} дней ${diffH.toString().padStart(2, '0')}:${diffM
.toString()
.padStart(2, '0')}:${diffS.toString().padStart(2, '0')}`}</p>
)
}
ReactDOM.render(<App date={new Date('Wed, 5 Oct 2022 00:00:00')}/>, document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Вариант 2 (расширенный)
Так же было бы не плохо остановить таймер, при достижении таймаута, чтобы не тратить ресурсы браузера впустую, поэтому в следующем снипете я вынес в локально состояние isTimeout и timerId и добавил еще один useEffect:
const { useState,useEffect } = React;
const App = ({ date }) => {
const [finishTime] = useState(date.getTime());
const [[diffDays, diffH, diffM, diffS], setDiff] = useState([0, 0, 0, 0]);
const [tick, setTick] = useState(false);
const [isTimeout, setIsTimeout] = useState(false);
const [timerId, setTimerID] = useState(0);
useEffect(() => {
const diff = (finishTime - new Date()) / 1000;
if (diff < 0) {
setIsTimeout(true);
return;
}
setDiff([
Math.floor(diff / 86400), // дни
Math.floor((diff / 3600) % 24),
Math.floor((diff / 60) % 60),
Math.floor(diff % 60)
]);
}, [tick, finishTime]);
useEffect(() => {
if (isTimeout) clearInterval(timerId);
}, [isTimeout, timerId]);
useEffect(() => {
const timerID = setInterval(() => {
setTick(!tick);
}, 1000);
setTimerID(timerID);
return () => clearInterval(timerID);
}, [tick]);
return (
<p>{`${diffDays} дней ${diffH
.toString()
.padStart(2, "0")}:${diffM
.toString()
.padStart(2, "0")}:${diffS.toString().padStart(2, "0")}`}</p>
);
};
ReactDOM.render(<App date={new Date('Wed, 5 Oct 2022 00:00:00')}/>, document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>