带有 pause/resume 计数器的 setTimeout 未在渲染时更新
setTimout with pause/resume counter not updating on render
我想设置一个可以在 React.js 中暂停和恢复的计数器。但是到目前为止,无论我尝试过什么,功能部分都在工作(pause/resume 正在工作),但它没有在渲染时更新计数器。下面是我的代码:
const ProgressBar = (props) => {
const [isPlay, setisPlay] = useState(false);
const [progressText, setProgressText] = useState(
props.duration ? props.duration : 20
);
var elapsed,
secondsLeft = 20;
const timer = () => {
// setInterval for every second
var countdown = setInterval(() => {
// if allowed time is used up, clear interval
if (secondsLeft < 0) {
clearInterval(countdown);
return;
}
// if paused, record elapsed time and return
if (isPlay === true) {
elapsed = secondsLeft;
return;
}
// decrement seconds left
secondsLeft--;
console.warn(secondsLeft);
}, 1000);
};
timer();
const stopProgress = () => {
setisPlay(!isPlay);
if (isPlay === false) {
secondsLeft = elapsed;
}
};
return (
<>
<p>{secondsLeft}</p>
</>
);
};
export default ProgressBar;
到目前为止,我已经尝试 React.js state、global var type、global let type、react ref 来使变量成为全局变量,但其中 none 有效..
那么基本上为什么您的示例不起作用?
您的 secondsLeft 变量未连接到您的 JSX。因此,每次您的组件重新渲染时,它都会创建一个值为 20 的新 secondsLeft 变量(因为重新渲染只是执行 returns JSX 的函数)
如何使您的变量值持久化 - useState or useReducer 钩子用于反应功能组件或基于 class 的状态。因此,React 将为您存储下一个重新渲染周期的所有值。
第二个问题是 React 不会重新渲染你的组件,它只是不知道什么时候应该重新渲染。那么是什么导致您的组件重新渲染 -
- 道具变化
- 状态变化
- 上下文更改
- adding/removing 您的组件来自 DOM
- 也许我遗漏了一些其他案例
所以下面的例子对我来说很好
import { useEffect, useState } from "react";
function App() {
const [pause, setPause] = useState(false);
const [secondsLeft, setSecondsLeft] = useState(20);
const timer = () => {
var countdown = setInterval(() => {
if (secondsLeft <= 0) {
clearInterval(countdown);
return;
}
if (pause === true) {
clearInterval(countdown);
return;
}
setSecondsLeft((sec) => sec - 1);
}, 1000);
return () => {
clearInterval(countdown);
};
};
useEffect(timer, [secondsLeft, pause]);
const pauseTimer = () => {
setPause((pause) => !pause);
};
return (
<div>
<span>Seconds Left</span>
<p>{secondsLeft}</p>
<button onClick={pauseTimer}>{pause ? "Start" : "Pause"}</button>
</div>
);
}
import React, { useState, useEffect } from "react";
import logo from "./logo.svg";
import "./App.css";
var timer = null;
function App() {
const [counter, setCounter] = useState(0);
const [isplayin, setIsPlaying] = useState(false);
const pause = () => {
setIsPlaying(false);
clearInterval(timer);
};
const reset = () => {
setIsPlaying(false);
setCounter(0);
clearInterval(timer);
};
const play = () => {
setIsPlaying(true);
timer = setInterval(() => {
setCounter((prev) => prev + 1);
}, 1000);
};
return (
<div className="App">
<p>Counter</p>
<h1>{counter}</h1>
{isplayin ? (
<>
<button onClick={() => pause()}>Pause</button>
<button onClick={() => reset()}>Reset</button>
</>
) : (
<>
{counter > 0 ? (
<>
<button onClick={() => play()}>Resume</button>
<button onClick={() => reset()}>Reset</button>
</>
) : (
<button onClick={() => play()}>Start</button>
)}
</>
)}
</div>
);
}
export default App;
我想设置一个可以在 React.js 中暂停和恢复的计数器。但是到目前为止,无论我尝试过什么,功能部分都在工作(pause/resume 正在工作),但它没有在渲染时更新计数器。下面是我的代码:
const ProgressBar = (props) => {
const [isPlay, setisPlay] = useState(false);
const [progressText, setProgressText] = useState(
props.duration ? props.duration : 20
);
var elapsed,
secondsLeft = 20;
const timer = () => {
// setInterval for every second
var countdown = setInterval(() => {
// if allowed time is used up, clear interval
if (secondsLeft < 0) {
clearInterval(countdown);
return;
}
// if paused, record elapsed time and return
if (isPlay === true) {
elapsed = secondsLeft;
return;
}
// decrement seconds left
secondsLeft--;
console.warn(secondsLeft);
}, 1000);
};
timer();
const stopProgress = () => {
setisPlay(!isPlay);
if (isPlay === false) {
secondsLeft = elapsed;
}
};
return (
<>
<p>{secondsLeft}</p>
</>
);
};
export default ProgressBar;
到目前为止,我已经尝试 React.js state、global var type、global let type、react ref 来使变量成为全局变量,但其中 none 有效..
那么基本上为什么您的示例不起作用? 您的 secondsLeft 变量未连接到您的 JSX。因此,每次您的组件重新渲染时,它都会创建一个值为 20 的新 secondsLeft 变量(因为重新渲染只是执行 returns JSX 的函数) 如何使您的变量值持久化 - useState or useReducer 钩子用于反应功能组件或基于 class 的状态。因此,React 将为您存储下一个重新渲染周期的所有值。 第二个问题是 React 不会重新渲染你的组件,它只是不知道什么时候应该重新渲染。那么是什么导致您的组件重新渲染 -
- 道具变化
- 状态变化
- 上下文更改
- adding/removing 您的组件来自 DOM
- 也许我遗漏了一些其他案例
所以下面的例子对我来说很好
import { useEffect, useState } from "react";
function App() {
const [pause, setPause] = useState(false);
const [secondsLeft, setSecondsLeft] = useState(20);
const timer = () => {
var countdown = setInterval(() => {
if (secondsLeft <= 0) {
clearInterval(countdown);
return;
}
if (pause === true) {
clearInterval(countdown);
return;
}
setSecondsLeft((sec) => sec - 1);
}, 1000);
return () => {
clearInterval(countdown);
};
};
useEffect(timer, [secondsLeft, pause]);
const pauseTimer = () => {
setPause((pause) => !pause);
};
return (
<div>
<span>Seconds Left</span>
<p>{secondsLeft}</p>
<button onClick={pauseTimer}>{pause ? "Start" : "Pause"}</button>
</div>
);
}
import React, { useState, useEffect } from "react";
import logo from "./logo.svg";
import "./App.css";
var timer = null;
function App() {
const [counter, setCounter] = useState(0);
const [isplayin, setIsPlaying] = useState(false);
const pause = () => {
setIsPlaying(false);
clearInterval(timer);
};
const reset = () => {
setIsPlaying(false);
setCounter(0);
clearInterval(timer);
};
const play = () => {
setIsPlaying(true);
timer = setInterval(() => {
setCounter((prev) => prev + 1);
}, 1000);
};
return (
<div className="App">
<p>Counter</p>
<h1>{counter}</h1>
{isplayin ? (
<>
<button onClick={() => pause()}>Pause</button>
<button onClick={() => reset()}>Reset</button>
</>
) : (
<>
{counter > 0 ? (
<>
<button onClick={() => play()}>Resume</button>
<button onClick={() => reset()}>Reset</button>
</>
) : (
<button onClick={() => play()}>Start</button>
)}
</>
)}
</div>
);
}
export default App;