Skip to main content

Debounce input keyup event in React

This is a follow-up to my previous blog on Using JavaScript Debounce, where I did a detailed explanation on how to use debounce to avoid sending excessive network requests.

Recently, I was working on a personal project using React and TypeScript, where I needed to code a registration form. The form included a username input field, which required sending a POST request to the server to check if the username already existed in the database. This is how I implemented in React.

./src/routes/register.tsx
import Input from "../components/Input";
import { useState, KeyboardEvent, FormEvent } from "react";

export default function RegisterForm() {
  const [isVerifyingUsername, setIsVerifyingUsername] = useState(false);
  const [usernameExists, setUsernameExists] = useState(false);

  let timeout: ReturnType<typeof setTimeout>;

  const debounce = (e: KeyboardEvent<HTMLInputElement>) => {
    const input = e.target as HTMLInputElement;
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      // show spinner whenever we're verifying username
      setIsVerifyingUsername(true);
      verifyUsername(input.value.trim());
    }, 500);
  };

  const verifyUsername = async (username: string) => {
    // need to clear out previous error message, if any
    setUsernameExists(false);

    // communicate with server to check if this username exists
    const res = await fetch(`/api/user/${username}`);
    if (res.ok) {
      // this user exits in database
      setUsernameExists(true);
    } else {
      setUsernameExists(false);
    }

    setIsVerifyingUsername(false);
  };

  const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
    // ...
  };

  return (
    <form onSubmit={handleSubmit}>
      <Input
        name="username"
        labelText="Username"
        id="register-username"
        placeholder="Your username"
        spinner={isVerifyingUsername ? true : false}
        onKeyUp={debounce}
        errorMessage={
          usernameExists ? (
            <span className="input-field__error">
              Username already exists.
            </span>
          ) : null
        }
      />
      {/* // ... other form elements */}
    </form>
  );
}