admin管理员组文章数量:1295857
enter image description here
Please look at the time printed on the console.
setInterval() looks like being called twice in on interval.
I attached my code below. I'd really appreciate it if you could give me a clue to the solution.
import React, {useState} from 'react';
import AppRouter from './Router';
import {authService} from '../fbase';
function App() {
console.log('App()');
const [isLoggedIn, setIsLoggedIn] = useState(authService.currentUser);
console.log(authService.currentUser);
setInterval(() => {
console.log(Date().toLocaleString());
console.log('In App.js > App()');
console.log(authService.currentUser);
}, 5000);
return <AppRouter isLoggedIn={isLoggedIn}></AppRouter>;
}
export default App;
enter image description here
Please look at the time printed on the console.
setInterval() looks like being called twice in on interval.
I attached my code below. I'd really appreciate it if you could give me a clue to the solution.
import React, {useState} from 'react';
import AppRouter from './Router';
import {authService} from '../fbase';
function App() {
console.log('App()');
const [isLoggedIn, setIsLoggedIn] = useState(authService.currentUser);
console.log(authService.currentUser);
setInterval(() => {
console.log(Date().toLocaleString());
console.log('In App.js > App()');
console.log(authService.currentUser);
}, 5000);
return <AppRouter isLoggedIn={isLoggedIn}></AppRouter>;
}
export default App;
Share
edited Oct 15, 2021 at 8:25
yoonjae
asked Oct 15, 2021 at 8:10
yoonjaeyoonjae
911 silver badge6 bronze badges
4
- 2 You should move calls like that into a useEffect function. – user5734311 Commented Oct 15, 2021 at 8:14
-
If you want
setInterval
to be called only once, you can convertApp
to a class based ponent, & callsetInterval
inside theponentDidMount
method. – Nice Books Commented Oct 15, 2021 at 8:15 - 3 @NiceBooks Or keep using hooks and call it inside a useEffect with an empty dependency array. – user5734311 Commented Oct 15, 2021 at 8:16
- 1 The reason is most likely <StrictMode> wrapping your <App> in index.js, see here: reactjs/docs/… – user5734311 Commented Oct 15, 2021 at 8:19
2 Answers
Reset to default 5Every time a state/prop changes your ponent will re-render. This means that everything that is not wrapped in a hook of some kind will also re-run. I'm not sure why this happens to you, maybe authService.currentUser
returns two different values, an initial (probably empty) one when mounting the ponent and the correct one after it does some calculations (maybe you request the user
from the back-end and it takes a while to get back the response -- some more code would be helpful here).
When the actual (correct) value will be returned from the authService
to your function ponent it will re-render thus running setInterval
again.
In order to make sure this never happens it's best to wrap our functionalities in a hook. If you want to run the setInterval
just ONCE (when mounting the ponent) we can wrap it in an useEffect
with an empty dependency array:
useEffect(() => {
setInterval(() => {
...
}, 5000)
), []}
This means the hook will only run when your ponent first mounts.
If you need to run it based on some prop change (like when isLoggedIn
changes from false
to true
or viceversa) you can add that to the dependency array and your interval will run every time isLoggedIn
state changes:
useEffect(() => {
setInterval(() => {
...
}, 5000)
}, [ isLoggedIn ])
If you only need to run that when isLoggedIn
changes from false
to true
you can also add an if
condition in your useEffect
like this:
useEffect(() => {
if (isLoggedIn) {
setInterval(() => {
...
}, 5000)
}
}, [ isLoggedIn ])
More than that, as Jose Antonio Castro Castro mentioned, in all of the above cases you need to use a cleanup function in order to stop the interval from running indefinitely when your ponent unmounts (because it has no way of knowing to stop by itself). This is achieved by returning a function from your effect:
useEffect(() => {
const interval = setInterval(() => {
...
}, 5000)
return () => clearInterval(interval);
), []}
Don't forget that every time your ponent feels like re-rendering, all of your constants and functions that are called directly at the root of your ponent will be re-declared / re-run again.
The useEffect
, useCallback
, useMemo
hooks help us with exactly that, but in different ways. Choose and use them wisely!
As in the ments, you need to call setInterval
when you mount the ponent, but you need to stop the timer when it is unmounted.
const App = (props) => {
const [count, setCount] = React.useState(0)
React.useEffect(function appRunTimer() {
// Creates a new timer when mount the ponent.
const timer = setInterval(() => {
console.log(Date().toLocaleString())
console.log('In App.js > App()')
}, 5000)
// Stops the old timer when umount the ponent.
return function stopTimer() {
clearInterval(timer)
}
}, [])
console.log('DRAW')
return (
<button onClick={() => {setCount(count + 1)}}>
Click to update ponent's state: You click me {count} time(s)
</button>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
<script crossorigin src="https://unpkg./react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg./react-dom@17/umd/react-dom.production.min.js"></script>
<div id="root"></div>
本文标签: javascriptsetInterval() called twice at an interval React jsStack Overflow
版权声明:本文标题:javascript - setInterval() called twice at an interval [React js] - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741626310a2389104.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论