Я делаю анимацию индикатора выполнения таймера в реакции. Я делаю это с помощью requestAnimationFrame(). У меня проблема в том, что я не могу остановить эту анимацию с помощью cancelAnimationFrame(), несмотря на то, что я установил идентификатор анимации, а затем ссылаюсь на этот идентификатор при отмене (handleStop func). Почему?
Редактировать: Хм, может быть, это остановит requestAnimationFrame(), но не остановит преобразование уже установленной анимации?
const { useState, useEffect } = React;
const App = () => {
const totalTime = 10000;
const [timeLeft, setTimeLeft] = useState(null);
const [timerId, setTimerId] = useState(null);
useEffect(() => {
setTimeLeft(totalTime);
const start = performance.now();
const animate = (time) => {
const elapsedTime = time - start;
setTimeLeft((prevTimeLeft) => {
if (prevTimeLeft !== null && prevTimeLeft > 0) {
const remainingTime = Math.max(totalTime - elapsedTime, 0);
requestAnimationFrame(animate);
return remainingTime;
}
return 0;
});
};
const id = requestAnimationFrame(animate);
setTimerId(id);
return () => {
cancelAnimationFrame(id);
};
}, []);
const handleStop = () => {
if (timerId) {
cancelAnimationFrame(timerId);
setTimerId(null);
}
};
return (
<div>
<div className = "progress-bar">
<div
style = {{
transform: `scaleX(${timeLeft ? timeLeft / totalTime : 0})`,
}}
/>
</div>
<button onClick = {handleStop}>Pause the animation</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));.progress-bar {
height: 10px;
width: 300px;
background-color: #fdb913;
border-radius: 10px;
overflow: hidden;
margin-top: 2rem;
margin-bottom: 3rem;
}
.progress-bar div {
background-color: grey;
height: 100%;
transform-origin: left center;
}<div id = "root">
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>
</div>


![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Возможно, вы можете попробовать эти шаги.
setState().useRef() вместо useState() для управления идентификатором таймера.Я написал код с этими шагами, и он хорошо работал в этой песочнице кода.
const timerRef = useRef(null);
useEffect(() => {
setTimeLeft(totalTime);
const start = performance.now();
const animate = (time) => {
const elapsedTime = time - start;
setTimeLeft((prevTimeLeft) => {
if (prevTimeLeft !== null && prevTimeLeft > 0) {
const remainingTime = Math.max(totalTime - elapsedTime, 0);
return remainingTime;
}
return 0;
});
timerRef.current = requestAnimationFrame(animate);
};
timerRef.current = requestAnimationFrame(animate);
return () => {
if (timerRef.current !== null) {
cancelAnimationFrame(timerRef.current);
timerRef.current = null;
}
};
}, []);
@Адриан Извините, вот новая ссылка. codeandbox.io/p/sandbox/nostalgic-wilson-yz3mpy
Предоставленная ссылка не работает