DEV Community

Kenneth Lum
Kenneth Lum

Posted on • Edited on

The declarative spirits of React Hooks

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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)