Ах, это проблема classi c при переходе от компонента Class к компоненту на основе хуков. Вам нужно будет выучить то, что вы знаете из компонента класса, чтобы понять, что произошло. (Чтобы узнать больше, я рекомендую вам прочитать эту статью, это действительно полезно: https://overreacted.io/a-complete-guide-to-useeffect/)
Так что в компоненте на основе хуков каждый раз, когда происходит рендеринг, React будет вызовите функцию компонента, чтобы узнать дерево DOM. Таким образом, в основном, каждый раз, когда вызывается функция, существует отдельный стек вызовов, и каждое состояние внутри функции будет иметь различное значение, и, следовательно, обратный вызов для setInterval
/ setTimer
будет иметь закрывающий доступ к значению, когда он создается (каждый раз, когда вызывается функция, будет отдельный обратный вызов startTimer
).
Вот где в игру вступает хук useEffect
. Вам нужно будет указать хуку useEffect
«обновить» обратный вызов, чтобы получить доступ к последней «версии» состояний. Проще говоря, вот мое предложение:
import React, { useState, useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
const Timer = (props) => {
let [previousTime, setPreviousTime] = useState(new Date(props.entry.timestamp).getTime());
let [elapsedTime, setElapsedTime] = useState(0);
let isRunning = useRef(true);
useEffect(() => {
function startTimer() {
console.log('previousTime', previousTime);
console.log('elapsedTime', elapsedTime);
if (isRunning.current) {
const now = Date.now();
setElapsedTime(elapsedTime + (now - previousTime));
setPreviousTime(now);
}
}
const timerInterval = setInterval(startTimer, 1000);
return () => clearInterval(timerInterval);
}, [previousTime, elapsedTime]); // The callback depends on those state, you need to put them here
function handlePause() {
isRunning.current = isRunning.current ? false : true
console.log('isRunning', isRunning.current);
if (!isRunning.current) {
setPreviousTime(Date.now());
console.log(previousTime);
}
}
let hours = 0, minutes = 0, seconds = 0;
let secondsDiffence, secondsText, minutesText, hoursText;
secondsDiffence = Math.floor(elapsedTime / 1000);
hours = Math.floor(secondsDiffence / 3600);
minutes = Math.floor((secondsDiffence - (hours * 3600)) / 60);
seconds = Math.floor(secondsDiffence - (hours * 3600) - (minutes * 60));
secondsText = seconds < 10 ? `0${seconds}` : `${seconds}`;
minutesText = minutes < 10 ? `0${minutes}` : `${minutes}`;
hoursText = hours < 10 ? `0${hours}` : `${hours}`;
console.log('elapsed outside -->', elapsedTime);
return (
<div>
<div id="timer">
{`${hoursText}:${minutesText}:${secondsText}`}
</div>
<button
id="pausePlay"
className="mainButton"
onClick={handlePause}>
{isRunning.current ? 'Pause' : 'Continue'}
</button>
<Link to="/" id="stopSave" className="mainButton" onClick={() => {
props.updateEntry(props.newEntry, elapsedTime, "elapsedTime");
props.submitEntry();
}}>Stop & Save</Link>
</div>
);
}
export default Timer;
Вот еще одна ссылка, которую вы можете оформить:
https://overreacted.io/making-setinterval-declarative-with-react-hooks/
https://reactjs.org/docs/hooks-reference.html