如何使反应倒数计时器
How make react countdown timer
我正在尝试用 React 做倒数计时器。它基本上是从 10 到 0 的倒计时,当 0 时我将调用一些函数。
我找到了一些非常适合我的例子:https://codesandbox.io/s/0q453m77nw?from-embed
但它是一个 class 组件,我不想用功能组件和挂钩来做,但我不能。
我试过:
function App() {
const [seconds, setSeconds] = useState(10);
useEffect(() => {
setSeconds(setInterval(seconds, 1000));
}, []);
useEffect(() => {
tick();
});
function tick() {
if (seconds > 0) {
setSeconds(seconds - 1)
} else {
clearInterval(seconds);
}
}
return (
<div className="App">
<div
{seconds}
</div>
</div>
);
}
export default App;
它从 10 倒数到 0 非常快,而不是 10 秒。
我错在哪里了?
你关心精度吗?如果是这样,您不需要 setInterval。如果您不关心精度(您可能不关心),那么您可以安排一个时间间隔调用 tick()
,而不是相反。
const TimeoutComponent extends Component {
constructor(props) {
super(props);
this.state = { countdown: 10 };
this.timer = setInterval(() => this.tick(), props.timeout || 10000);
}
tick() {
const current = this.state.countdown;
if (current === 0) {
this.transition();
} else {
this.setState({ countdown: current - 1 });
}
}
transition() {
clearInterval(this.timer);
// do something else here, presumably.
}
render() {
return <div className="timer">{this.state.countDown}</div>;
}
}
这有点取决于你的逻辑。在目前的情况下,你的 useEffect
你 运行 你的 tick
方法在每个渲染上都是 运行ning。您可以在下面找到一个简单的示例。
function App() {
const [seconds, setSeconds] = useState(10);
const [done, setDone] = useState(false);
const foo = useRef();
useEffect(() => {
function tick() {
setSeconds(prevSeconds => prevSeconds - 1)
}
foo.current = setInterval(() => tick(), 1000)
}, []);
useEffect(() => {
if (seconds === 0) {
clearInterval(foo.current);
setDone(true);
}
}, [seconds])
return (
<div className="App">
{seconds}
{done && <p>Count down is done.</p>}
</div>
);
}
第一个效果是倒计时。使用回调一来设置状态,因为间隔创建了一个闭包。在第二个效果中,我们正在检查我们的条件。
似乎多个 useEffect
挂钩导致每秒 运行 倒计时不止一次。
这是一个简化的解决方案,我们检查 useEffect
挂钩中的 seconds
并且:
- 使用
setTimeout
1秒后更新seconds
,或者
- 做点别的(倒计时结束时要调用的函数)
此方法有一些缺点,请参见下文。
function App() {
const [seconds, setSeconds] = React.useState(10);
React.useEffect(() => {
if (seconds > 0) {
setTimeout(() => setSeconds(seconds - 1), 1000);
} else {
setSeconds('BOOOOM!');
}
});
return (
<div className="App">
<div>
{seconds}
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
缺点
使用 setInterval
的缺点是它可能会被停止 - 例如,组件被卸载,您导航到不同的选项卡,或关闭您的计算机。如果计时器需要更高的鲁棒性,更好的选择是在状态中存储一个 endTime
(如全局存储或上下文)并让您的组件根据 endTime
检查当前时间以计算倒计时.
我正在尝试用 React 做倒数计时器。它基本上是从 10 到 0 的倒计时,当 0 时我将调用一些函数。
我找到了一些非常适合我的例子:https://codesandbox.io/s/0q453m77nw?from-embed 但它是一个 class 组件,我不想用功能组件和挂钩来做,但我不能。
我试过:
function App() {
const [seconds, setSeconds] = useState(10);
useEffect(() => {
setSeconds(setInterval(seconds, 1000));
}, []);
useEffect(() => {
tick();
});
function tick() {
if (seconds > 0) {
setSeconds(seconds - 1)
} else {
clearInterval(seconds);
}
}
return (
<div className="App">
<div
{seconds}
</div>
</div>
);
}
export default App;
它从 10 倒数到 0 非常快,而不是 10 秒。 我错在哪里了?
你关心精度吗?如果是这样,您不需要 setInterval。如果您不关心精度(您可能不关心),那么您可以安排一个时间间隔调用 tick()
,而不是相反。
const TimeoutComponent extends Component {
constructor(props) {
super(props);
this.state = { countdown: 10 };
this.timer = setInterval(() => this.tick(), props.timeout || 10000);
}
tick() {
const current = this.state.countdown;
if (current === 0) {
this.transition();
} else {
this.setState({ countdown: current - 1 });
}
}
transition() {
clearInterval(this.timer);
// do something else here, presumably.
}
render() {
return <div className="timer">{this.state.countDown}</div>;
}
}
这有点取决于你的逻辑。在目前的情况下,你的 useEffect
你 运行 你的 tick
方法在每个渲染上都是 运行ning。您可以在下面找到一个简单的示例。
function App() {
const [seconds, setSeconds] = useState(10);
const [done, setDone] = useState(false);
const foo = useRef();
useEffect(() => {
function tick() {
setSeconds(prevSeconds => prevSeconds - 1)
}
foo.current = setInterval(() => tick(), 1000)
}, []);
useEffect(() => {
if (seconds === 0) {
clearInterval(foo.current);
setDone(true);
}
}, [seconds])
return (
<div className="App">
{seconds}
{done && <p>Count down is done.</p>}
</div>
);
}
第一个效果是倒计时。使用回调一来设置状态,因为间隔创建了一个闭包。在第二个效果中,我们正在检查我们的条件。
似乎多个 useEffect
挂钩导致每秒 运行 倒计时不止一次。
这是一个简化的解决方案,我们检查 useEffect
挂钩中的 seconds
并且:
- 使用
setTimeout
1秒后更新seconds
,或者 - 做点别的(倒计时结束时要调用的函数)
此方法有一些缺点,请参见下文。
function App() {
const [seconds, setSeconds] = React.useState(10);
React.useEffect(() => {
if (seconds > 0) {
setTimeout(() => setSeconds(seconds - 1), 1000);
} else {
setSeconds('BOOOOM!');
}
});
return (
<div className="App">
<div>
{seconds}
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
缺点
使用 setInterval
的缺点是它可能会被停止 - 例如,组件被卸载,您导航到不同的选项卡,或关闭您的计算机。如果计时器需要更高的鲁棒性,更好的选择是在状态中存储一个 endTime
(如全局存储或上下文)并让您的组件根据 endTime
检查当前时间以计算倒计时.