Problem
I am writing a simple count down timer in React:
index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import bootstrap from "bootstrap/dist/css/bootstrap.css";
import App from "./App";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);
App.js:
import React, { useEffect, useState } from "react";
const App = () => {
const oneSec = 1000;
const [secCount, setSecCount] = useState(60);
const [minCount, setMinCount] = useState(60);
const [hrCount, setHrCount] = useState(24);
useEffect(() => {
const timer; //<= here is my problem.
if (secCount > 0) {
timer = setInterval(() => {
setSecCount(secCount - 1);
}, oneSec);
}
if (secCount === 0 && minCount > 0) {
timer = setInterval(() => {
setSecCount(60);
}, oneSec);
}
return () => clearInterval(timer);
}, [secCount]);
useEffect(() => {
const timer =
minCount > 0 &&
setInterval(() => {
setMinCount(minCount - 1);
}, 60 * oneSec);
return () => clearInterval(timer);
}, [minCount]);
return (
<div>
{minCount}:{secCount}
</div>
);
};
export default App;
I am having a hard time with my useEffect
hooks. The first useEffect
hook is supposed to update the second field, the logic is simply:
- if
secCount
is bigger than 0, continue to countdown every second - if
secCount
is zero andminCount
is bigger than 0, resetsecCount
to 60 and continue to countdown.
But since there are two branches in my first useEffect
hook, I need to declare the timer variable and reassign it later. Can I get away with declaring it as let timer
? A const variable does not allow me to change its value.
Solution
- const
Creates a constant whose scope can be eitherglobal
orlocal
to the block in which it is declared. Aninitializer
for a constant is required. You must specify its value in the same statement in which it’s declared.
// wrong
const timer;
// Uncaught SyntaxError: Missing initializer in const declaration
// right
const timer = 60;
- let
Allows you to declare variables that are limited to a scope of ablock
statement, or expression on which it is used, unlike thevar
keyword, which defines a variable globally, or locally to an entire function regardless of block scope. Please note that alet
variable is initialized to a value only when a parser evaluates it.
function do_something() {
console.log(bar); // undefined
console.log(foo); // ReferenceError
var bar = 1;
let foo = 2;
};
With that said, change the declaration to let timer;
// Within the first `useEffect`
useEffect(() => {
let timer; // change this
if (secCount > 0) {
timer = setInterval(() => {setSecCount(secCount - 1)}, oneSec);
}
if (secCount === 0 && minCount > 0) {
timer = setInterval(() => {setSecCount(60)}, oneSec);
}
return () => clearInterval(timer);
}, [secCount]);
```