Suppose the teacher asked you to write a webpage that can show the current time, updated every second, in an exam.
So you wrote
export default function App() {
const s = useCurrentTime();
return (
<div className="App">
{s}
</div>
);
}
So the teacher may say, "wrong, wrong, wrong". It shows something, and it won't update itself.
If it is plain JavaScript, it would be wrong, because things happen imperatively, and the code above does it once only, not updating the time every second.
So you can explain, "I am sorry, this useCurrentTime()
is not imperative, but declarative. It is the current time, every second in real time."
How can that be? That's how React is like: it is declarative, but up to a certain point, the programmer needs to make the declarative become true by imperative actions.
The part that bridges between them is:
function useCurrentTime() {
const [timeString, setTimeString] = useState("");
useEffect(() => {
const intervalID = setInterval(() => {
setTimeString(new Date().toLocaleTimeString());
}, 100);
return () => clearInterval(intervalID);
}, []);
return timeString;
}
It sets up a repeated action, so that every 100ms, it sets its state to the locale time string. If we don't care about the time off by a bigger fraction of a second, we can use 300
, 500
, or 667
instead. I don't recommend using 1000
because there can be a case where it was 12:01:02.998, and the 1000ms turns out to be 1016ms due to some delay for the interval event, and then the time would go from 12:01:02 to 12:01:04, assuming the time is by flooring the second.
If that string is the same as before, it won't trigger a re-render of App
. When the "state", the string, has changed, then App
is re-rendered.
Demo: https://codesandbox.io/s/twilight-waterfall-kbrb0?file=/src/App.js
Dan Abramov wrote about how he'd implement useInterval()
as something that is declarative using this methodology.
Top comments (0)