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
- Collects data from the user.
- Then makes a HTTP call to the API endpoint to send that data to the server.
- So that it can then store it in a database which can be fetched again later in the application.
In the case of failures -
- Maybe API returned an error in its response.
- A value passed in a field of the form failed a validation check.
- Maybe we got a 500 Server Error.
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 -
- Create a React State to store the notification message.
- Update this state with the notification message after form submission failure or success.
- Add a useEffect to reset the React State back to its default value after x seconds, whenever state is updated.
- 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!