使用 setInterval() 制作带有 ReactJS 挂钩的会话计时器:错误消息、不规则计数和 "null" 输出
Using setInterval() to make a session timer with ReactJS hooks: error messages, irregular counting and "null" output
我正在尝试制作一个计时器,该计时器将在用户加载主页时开始(在 00:00),每秒递增一次,并在用户转到其他页面时重置为 00:00页。
这是我的最新代码:
const [ timerCount, increaseTimer ] = useState(0);
function timerItself() {
function timerIncrement() {
var currentTimerCount = timerCount;
increaseTimer(currentTimerCount + 1);
};
setInterval(() => timerIncrement, 1000);
clearInterval(timerIncrement);
return;
}
function pageHome() {
var timerMinutes = JSON.stringify(Math.floor(timerItself / 60));
var timerSeconds = JSON.stringify(timerItself % 60);
timerItself();
return (
<div classname="App">
<header className="App-header">
<h1>Hello world!</h1>
<img src={logo} className="App-logo" alt="logo" />
<p>{timerMinutes.padStart(2, '0')}:{timerSeconds.padStart(2, '0')}</p>
<p>
<button onClick={(() => changePage('About'))}>
About
</button>
<button onClick={(() => changePage('Help'))}>
Help
</button>
</p>
</header>
</div>
);
}
之前我将 setInterval()
包裹在 const
中,如下所示:
const timer = setInterval(() => increaseTimer(timerCount + 1), 1000);
并尝试将 clearInterval()
放入按钮的 onClick 函数中,认为这只会重置计时器。
输出有奇怪的行为:计时器会以不规则的间隔计数,从 00:03 而不是 00:00 开始非常慢,然后变得非常快。显示的时间顺序是一致的,但我无法将其识别为数学序列:3、7、11、29……81……并在大约 30 秒内达到非常高的数字。无法弄清楚代码中数字的来源。
我做了更多的阅读,得出的结论是 timer
同时启动了多个计时器,并以某种方式将它们的输出加在一起。所以我写了 timerItself()
,里面有一个 clearInterval()
我假设它也会每秒触发一次以清除旧计时器并为新计时器清理。但是现在根本没有计数,计时器的字符串化输出是“null:null”。
我对 clearInterval()
应该放在哪里感到困惑,因为我认为这是解决这个问题的主要关键。如果有任何帮助,我将不胜感激。
要创建一个在渲染组件时开始的间隔,您可以使用 useEffect Hook,并将 timerCount 作为依赖项。因为当您第一次渲染组件时,您想要启动计数器,并且随着您增加计时器,您希望间隔继续。
import React, { useState, useEffect } from 'react';
export default function Home() {
const [timerCount, increaseTimer] = useState(0);
useEffect(() => {
let myTimerId;
myTimerId = setInterval(() => {
increaseTimer(timerCount + 1);
}, 1000);
return () => clearInterval(myTimerId);
}, [timerCount]);
return (
<div>
<h1>Timer {timerCount}</h1>
</div>
);
}
export function Other() {
return <div>This is the other Page</div>;
}
useEffect Hook 返回的箭头函数是一个清理函数,它将清除 TheInterval 以防止内存泄漏。
这里是 App.js 组件
import React from 'react';
import { BrowserRouter as Router, Link, Route, Switch } from 'react-router-dom';
import Home, { Other } from './Home';
export default function App() {
return (
<>
<Router>
<ul>
<li>
<Link to="/home">Home</Link>
</li>
<li>
<Link to="/other">Other</Link>
</li>
</ul>
<Switch>
<Route exact path="/home" component={Home} />
<Route exact path="/other" component={Other} />
</Switch>
</Router>
</>
);
}
我使用了一个名为 react-router-dom 的库来在您的应用程序的路径之间导航,而无需发出新请求。
参考:https://reactrouter.com/web/guides/quick-start
和
使用效果:https://reactjs.org/docs/hooks-effect.html
// 另外我建议你以这种方式命名更新状态的函数:
const [myExampleState, setMyExampleState] = useState('Example1');
setMyExampleState('Example2');
- 希望我有所帮助。 (同时查看生命周期以更好地了解 React 的工作原理;D)
是的,setinterval 不能很好地处理 hooks。即使使用 useEffect 解决方案,您也会浪费时间。如果间隔最多为 3/4 秒,则出于任何原因的重新渲染将破坏并重新创建计时器,使其再次回到零。大量重新渲染,间隔开,有效地使计时器瘫痪。
这可能是将计时器放在组件外部的一个好例子。它仍然在组件的范围内,不受其控制。对于导航上调用的任何函数都是一样的。
已解决!
这段代码对我的用途来说效果很好:
const [ timer, changeTimer ] = useState(0);
var currentTimerCount = timer;
useEffect(() => {
if (page !== 'Home')
changeTimer(0);
if (page == 'Home')
currentTimerCount = setInterval(() => {changeTimer(prevTimer => prevTimer + 1)}, 1000);
return () => clearInterval(currentTimerCount);
});
var timerMinutes = JSON.stringify(Math.floor(currentTimerCount / 60));
var timerSeconds = JSON.stringify(currentTimerCount % 60);
然后像以前一样调用 timerMinutes 和 timerSeconds。
感谢所有回答的人!
我正在尝试制作一个计时器,该计时器将在用户加载主页时开始(在 00:00),每秒递增一次,并在用户转到其他页面时重置为 00:00页。
这是我的最新代码:
const [ timerCount, increaseTimer ] = useState(0);
function timerItself() {
function timerIncrement() {
var currentTimerCount = timerCount;
increaseTimer(currentTimerCount + 1);
};
setInterval(() => timerIncrement, 1000);
clearInterval(timerIncrement);
return;
}
function pageHome() {
var timerMinutes = JSON.stringify(Math.floor(timerItself / 60));
var timerSeconds = JSON.stringify(timerItself % 60);
timerItself();
return (
<div classname="App">
<header className="App-header">
<h1>Hello world!</h1>
<img src={logo} className="App-logo" alt="logo" />
<p>{timerMinutes.padStart(2, '0')}:{timerSeconds.padStart(2, '0')}</p>
<p>
<button onClick={(() => changePage('About'))}>
About
</button>
<button onClick={(() => changePage('Help'))}>
Help
</button>
</p>
</header>
</div>
);
}
之前我将 setInterval()
包裹在 const
中,如下所示:
const timer = setInterval(() => increaseTimer(timerCount + 1), 1000);
并尝试将 clearInterval()
放入按钮的 onClick 函数中,认为这只会重置计时器。
输出有奇怪的行为:计时器会以不规则的间隔计数,从 00:03 而不是 00:00 开始非常慢,然后变得非常快。显示的时间顺序是一致的,但我无法将其识别为数学序列:3、7、11、29……81……并在大约 30 秒内达到非常高的数字。无法弄清楚代码中数字的来源。
我做了更多的阅读,得出的结论是 timer
同时启动了多个计时器,并以某种方式将它们的输出加在一起。所以我写了 timerItself()
,里面有一个 clearInterval()
我假设它也会每秒触发一次以清除旧计时器并为新计时器清理。但是现在根本没有计数,计时器的字符串化输出是“null:null”。
我对 clearInterval()
应该放在哪里感到困惑,因为我认为这是解决这个问题的主要关键。如果有任何帮助,我将不胜感激。
要创建一个在渲染组件时开始的间隔,您可以使用 useEffect Hook,并将 timerCount 作为依赖项。因为当您第一次渲染组件时,您想要启动计数器,并且随着您增加计时器,您希望间隔继续。
import React, { useState, useEffect } from 'react';
export default function Home() {
const [timerCount, increaseTimer] = useState(0);
useEffect(() => {
let myTimerId;
myTimerId = setInterval(() => {
increaseTimer(timerCount + 1);
}, 1000);
return () => clearInterval(myTimerId);
}, [timerCount]);
return (
<div>
<h1>Timer {timerCount}</h1>
</div>
);
}
export function Other() {
return <div>This is the other Page</div>;
}
useEffect Hook 返回的箭头函数是一个清理函数,它将清除 TheInterval 以防止内存泄漏。
这里是 App.js 组件
import React from 'react';
import { BrowserRouter as Router, Link, Route, Switch } from 'react-router-dom';
import Home, { Other } from './Home';
export default function App() {
return (
<>
<Router>
<ul>
<li>
<Link to="/home">Home</Link>
</li>
<li>
<Link to="/other">Other</Link>
</li>
</ul>
<Switch>
<Route exact path="/home" component={Home} />
<Route exact path="/other" component={Other} />
</Switch>
</Router>
</>
);
}
我使用了一个名为 react-router-dom 的库来在您的应用程序的路径之间导航,而无需发出新请求。
参考:https://reactrouter.com/web/guides/quick-start
和
使用效果:https://reactjs.org/docs/hooks-effect.html
// 另外我建议你以这种方式命名更新状态的函数:
const [myExampleState, setMyExampleState] = useState('Example1');
setMyExampleState('Example2');
- 希望我有所帮助。 (同时查看生命周期以更好地了解 React 的工作原理;D)
是的,setinterval 不能很好地处理 hooks。即使使用 useEffect 解决方案,您也会浪费时间。如果间隔最多为 3/4 秒,则出于任何原因的重新渲染将破坏并重新创建计时器,使其再次回到零。大量重新渲染,间隔开,有效地使计时器瘫痪。
这可能是将计时器放在组件外部的一个好例子。它仍然在组件的范围内,不受其控制。对于导航上调用的任何函数都是一样的。
已解决!
这段代码对我的用途来说效果很好:
const [ timer, changeTimer ] = useState(0);
var currentTimerCount = timer;
useEffect(() => {
if (page !== 'Home')
changeTimer(0);
if (page == 'Home')
currentTimerCount = setInterval(() => {changeTimer(prevTimer => prevTimer + 1)}, 1000);
return () => clearInterval(currentTimerCount);
});
var timerMinutes = JSON.stringify(Math.floor(currentTimerCount / 60));
var timerSeconds = JSON.stringify(currentTimerCount % 60);
然后像以前一样调用 timerMinutes 和 timerSeconds。
感谢所有回答的人!