Hi, I am Sanjeet Tiwari...
Let's talk about

Back to Blog

React Hook for a Timed State

First of all, I acknowledge that the title of this blog might seem very click-baity.

I’ll explain what I am trying to demonstrate here by first explaining the why.

Problem Statement

As a developer, while working on many projects, I have developed several forms which

In the case of failures -

the usual requirment is to show an error notification UI to the user, usually at the bottom of the submit button, to inform the user about the failure.

This is all pretty standard stuff, right ?

I have come across a specific requirement about this error notification UI multiple times, which is, to show it only for x seconds.

And not just with errors, but sometimes in the case of successful form submissions as well.

But now, you must be thinking…

Why not use a Toast ?

The requirements that I mentioned didn’t want me to have a common UI which is positioned at the corner of the screen, but at individual field level.

However, a similar scenario can occur wherein the UI governed by these timed states might not be common at all, and need to be created individually.

The Hook

Well, there can be many solutions that tackles this problem.

As per my experience, the most concise one being -

  1. Create a React State to store the notification message.
  2. Update this state with the notification message after form submission failure or success.
  3. Add a useEffect to reset the React State back to its default value after x seconds, whenever state is updated.
  4. Show the notification UI only when state holds a value.

Why not just move all of this to a hook ?

// useTimedNotif.ts

import { useEffect, useState } from "react";

const DEFAULT_DURATION = 1000;

/**
 * This hook lets you have manage a notification state which will reset after specified duration
 * @param duration miliseconds after which notification should reset
 * @returns notification and notification setter
 */
export default function useTimedNotif(duration: number = DEFAULT_DURATION) {
  const [notif, setNotif] = useState("");

  useEffect(() => {
    if (!notif) return;

    // adding a validation check and
    // defaulting to 1 sec if a negative value is provided
    const validatedDuration = duration > 0 ? duration : DEFAULT_DURATION;

    // start a timer
    // which will reset the notif after
    // `duration` seconds
    const timer = setTimeout(() => {
      setNotif("");
    }, validatedDuration);

    return () => {
      // clearing any existing timers
      // when this side effect executes again
      clearTimeout(timer);
    };
  }, [notif, duration]);

  return {
    notif,
    setNotif,
  };
}

Usage

This hook can be used in any component which can then use the notif state returned by hook, to act as a trigger to show the notification UI.

The notification message that needs to be displayed can be set via setNotif returned by the hook.

Lets look at an example -

export default function MyApp() {
  const { notif: error, setNotif: setError } = useTimedNotif(); // This is my hook that we talked about

  function handleFormSubmit() {
    // ...
    setError("Age value is not correct");
    // ...
  }

  return (
  <form>
    .
    .
    {error && (<div className="error-message">{error}</div>)}
  </form>
  )
}

This way, the error message UI will be displayed for 1 second before getting reset again.

Please note, that we can set our own duration for which we need to show the notification message.

Special Note

In some cases, I have personally taken an offense while witnessing the bottom section of the page jumping due to the error UI coming in and out of existence.

I personally prefer just hiding the error div via opacity or some other way, to save the UI from bouncing.

Thats it! Thanks for your time, and thank me later!

Last updated on 22-12-2024