I made this component representing a HH:MM clock.
It’s re-rendering every second. I would like to be re-rendered every minute.
A tooltip is attached to it. The tooltip cannot be shown because of the re-render.
How can I handle this situation ?
import TooltipComp from '@components/Shared/TooltipComp'
import React, { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
const Clock = () => {
const [Time, setTime] = useState(new Date())
const { t } = useTranslation();
useEffect(() => {
let now = new Date()
while (now.getSeconds() !== 0) {
const interval = window.setInterval(() => {now = new Date()}, 1000)
return () => window.clearInterval(interval);
}
setTime(now);
}, [])
const formatTime = (time) => {
return time < 10 ? `0${time}` : time
}
const date = Time.toLocaleDateString(t('locale'), {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
})
return (
<>
<TooltipComp text={date}>
<div style={{fontSize: "9px", fontFamily: "PX", cursor: "default"}}>
{formatTime(Time.getHours())}
 : 
{formatTime(Time.getMinutes())}
</div>
</TooltipComp>
</>
)
}
export default Clock
I already tried using useMemo hooks, and multiple variations of the useEffect one.
2
Answers
There should not be an issue with re-rendering every second. Infact in a clock like this that should be desirable. Have you checked if your clock is working?
You seem to return out of your useEffect before you’ve set state. Which means your UI would not be receiving any state updates.
I tried to continue with your code, However, it found little difficult to understand. The while loop is something to be reviewed. Therefore reworked the implementation as below. Please see if it makes sense to you.
The app will move along with the system clock as shown in the trial run output below :
Browser display – the clock works in synch with the system clock
Coding highlights
a. useEffect has been used to synch with the change in time.
b. setTimeout has been used to synch the time with the first next minute from the start.
Let us say the app has started at 14:20:20 HH:mm:ss, it means 20 seconds have already been elapsed from 20th minute of 14th hour. Therefore the initial time displayed by the app will be 14:20. Now there is 40 seconds to elapse to the next minute. It means by elapsing 40 seconds from the start time, there should be a state change triggered by the code. This code has been setup by the async function setTimeout which will run the given code only once. This is the reason for using a expression like 1000 * (60 – startTime.getSeconds()) to set its time.
c. Once the app has been in synch with the system time by the step b, the subsequent state changes are required exactly in every one minute. This will be done repeatedly by the code given in setInterval function by firing in every minute. Please take note of the expression 1000 * 60 – one minute, used here.
b. forceRender is the only state used in the app which is just to trigger a render, and its value has been set with a random number.
App.js