1

In my React application, I'm trying to make some text dynamic based on the current user's time, utilizing the Date object in JS. For example, new Date().getHours().

When it is 11:59am, I want the text "Morning" to be rendered, but AS SOON as the time changes to 12:00pm, I want "Afternoon" to be rendered to the screen.

Currently, I have the following implementation using setInterval and checking the current hour every second, I believe this is not the best way as it is calling the useEffect hook too frequently? But without this setInterval, I have to refresh the page to see the new changes. Is there a better way to do this?

export const myFunction = () => {
    const [myText, setMyText] = useState("");
    const [localTime, setLocalTime] = useState(new Date().getHours());

    useEffect(() => {
        function timeInterval() {
            const currentHour = new Date().getHours();
            if (localTime !== currentHour) {setLocalTime(currentHour);}
            if (localTime >= 1 && localTime < 12) {setMyText("Morning");}
            else if (localTime >= 12 && localTime < 17) {setMyText("Afternoon");}
        }
        timeInterval();
        const myInterval = setInterval(timeInterval, 1000);
        return () => clearInterval(myInterval);
    }, [myText, localTime]);
    
    return (
        <h1>
            {myText}
        </h1>
           );
}
  • Per the answers [here](https://stackoverflow.com/questions/3367505/detecting-changes-to-system-time-in-javascript), I think your approach is fine. Although that post is very old, so maybe someone has a new, better way to do it. Because you've included your `localTime` and `myText` as dependencies on your useEffect though, I think you will probably end up with more than one `setInterval` running simultaneously. Perhaps an approach like [this one](https://medium.com/programming-essentials/how-to-create-a-digital-clock-with-react-hooks-aa30f76cfe3f) might be better – Jake Apr 13 '23 at 23:47
  • 1
    Maybe instead of a timer every 1 second, you could use a single `setTimeout`; so for example, if the user launches the page at 11:15am, you could start a timer for 45 minutes, and then update the text once. Whether this is actually a good idea probably depends on the rest of your project/goal – Jake Apr 13 '23 at 23:48

1 Answers1

0

You can set up the interval once when the component is first mounted (without depending on anything else). There is also no need for putting the current hour in state.

useEffect(() => {
    function timeInterval() {
      const currentHour = new Date().getHours();
      setLocalTime(currentHour); // not necessary, unless it's being displayed somewhere
      // no need to compare currentHour with localTime
      // React will not rerender when setting state to the same as the previous value
      if (currentHour >= 1 && currentHour < 12) setMyText("Morning");
      else if (currentHour >= 12 && currentHour < 17) setMyText("Afternoon");
    }
    timeInterval();
    const id = setInterval(timeInterval, 1000);
    return () => clearInterval(id);
}, []);
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
  • Do you think it is bad performance for the app to keep calling the timeInterval function every second to check the time? Or it won't use much memory/cpu? – HackerMan33453 Apr 14 '23 at 16:38
  • 1
    @HackerMan33453 It probably isn't a huge issue, but it's better to only set up the interval once, instead of every time the state changes. Also, checking every second isn't terrible, but the interval period could certainly be lengthened since you only care about the hour. – Unmitigated Apr 14 '23 at 19:12