DEV Community

Cover image for Validate Form during Browser Idle for Performance Optimization
nuko_suke
nuko_suke

Posted on

Validate Form during Browser Idle for Performance Optimization

When do you validate the value entered by the user in the input form? 🤔
Perhaps, you check it at real timing, or just after tapping a button like "Submit" .

I suggest new way of form validation which uses requestIdleCallback .

https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback

By checking the data entered by the user while the browser is idle, the result of the validation is already available when the user taps a button like "Confirm" .
It makes us faster response to button taps.

This article introduces the example using idle-task (v3.3.1) which wraps requestIdleCallback conveniently.

Example of React

This is the example of react hooks.

import { useRef, useEffect } from "react";
import { setIdleTask, forceRunIdleTask, cancelIdleTask } from "idle-task";

export default function useValidateWhenIdle(
  input: string,
  validate: (input: string) => boolean
) {
  const idleTaskIdRef = useRef(NaN);

  useEffect(() => {
    const validateTask = () => validate(input);
    idleTaskIdRef.current = setIdleTask(validateTask);
    return () => {
      cancelIdleTask(idleTaskIdRef.current);
    };
  }, [input, validate]);

  return () => forceRunIdleTask(idleTaskIdRef.current);
}
Enter fullscreen mode Exit fullscreen mode

The component that uses this hooks is as follows.

import "./styles.css";
import useValidateWhenIdle from "./useValidateWhenIdle";
import { useState, ChangeEventHandler, FormEventHandler } from "react";
import { configureIdleTask } from "idle-task";

configureIdleTask({
  debug: true
});

const validateUserName = (userName: string): boolean => {
  return /^[a-zA-Z]+$/.test(userName);
};

export default function App() {
  const [userName, setUserName] = useState("");
  const validateUserNameWhenIdle = useValidateWhenIdle(userName, validateUserName);
  const handleUserNameChange: ChangeEventHandler<HTMLInputElement> = ({
    target
  }) => {
    setUserName(target.value);
  };
  const handleSubmit: FormEventHandler<HTMLFormElement> = async (event) => {
    event.preventDefault();
    const isValid = await validateUserNameWhenIdle();
    if (isValid) {
      alert(`YourName: ${userName}`);
    } else {
      alert(`${userName} is invalid`);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        FirstName:
        <input type="text" value={userName} onChange={handleUserNameChange} />
      </label>
      <input type="submit" value="Submit" />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

First, let's take a closer look at the useValidateWhenIdle hooks.

useValidateWhenIdle takes two arguments.

  • input : String to be validated
  • validate : Function that takes a string to be validated and validates it

The return value is the function which can get validation result.

We will also take a closer look at the internal processing.

  const idleTaskIdRef = useRef(NaN);

  useEffect(() => {
    const validateTask = () => validate(input);
    idleTaskIdRef.current = setIdleTask(validateTask);
    return () => {
      cancelIdleTask(idleTaskIdRef.current);
    };
  }, [input, validate]);
Enter fullscreen mode Exit fullscreen mode

The setIdleTask of idle-task makes the argument function run while the browser is idle.
setIdleTask(validateTask) will cause validateTask, a function that validates user input values, to be executed while the browser is idle.

The return value of setIdleTask is an ID.
This ID can be used to cancel the execution of an idle function or to retrieve the result of an idle function.

We uses useRef to keep track of the ID.
Then, useEffect makes us ensure that validation is performed while the browser is idle each time a user-entered value is changed.
In the useEffect cleanup function, we use cancelIdleTask to cancel the target process if it has not yet been executed.

  return () => forceRunIdleTask(idleTaskIdRef.current);
Enter fullscreen mode Exit fullscreen mode

The result of a function registered with setIdleTask can be retrieved with forceRunIdleTask.
If the function has already been executed while the browser is idle, the result is returned; if it has not yet been executed, it is executed immediately.

Next, let's take a closer look at the components on the side that use useValidateWhenIdle hooks.

import "./styles.css";
import useValidateWhenIdle from "./useValidateWhenIdle";
import { useState, ChangeEventHandler, FormEventHandler } from "react";
import { configureIdleTask } from "idle-task";

configureIdleTask({
  debug: true
});

const validateUserName = (userName: string): boolean => {
  return /^[a-zA-Z]+$/.test(userName);
};

export default function App() {
  const [userName, setUserName] = useState("");
  const validateUserNameWhenIdle = useValidateWhenIdle(userName, validateUserName);
  const handleUserNameChange: ChangeEventHandler<HTMLInputElement> = ({
    target
  }) => {
    setUserName(target.value);
  };
  const handleSubmit: FormEventHandler<HTMLFormElement> = async (event) => {
    event.preventDefault();
    const isValid = await validateUserNameWhenIdle();
    if (isValid) {
      alert(`YourName: ${userName}`);
    } else {
      alert(`${userName} is invalid`);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        FirstName:
        <input type="text" value={userName} onChange={handleUserNameChange} />
      </label>
      <input type="submit" value="Submit" />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

This is an example of a basic React form implementation.
What are the key points?

const validateUserNameWhenIdle = useValidateWhenIdle(userName, validateUserName);
Enter fullscreen mode Exit fullscreen mode

The useValidateWhenIdle appears.
The first argument is a string to be validated, and the second argument is a function that defines the validation logic.
And the return value is function which can get the result of
the validation.
It is used when the Submit button is pressed as follows.

  const handleSubmit: FormEventHandler<HTMLFormElement> = async (event) => {
    event.preventDefault();
    const isValid = await validateUserNameWhenIdle();
    if (isValid) {
      alert(`YourName: ${userName}`);
    } else {
      alert(`${userName} is invalid`);
    }
  };
Enter fullscreen mode Exit fullscreen mode

When the Submit button is pressed, we get the validation result by using async/await.

The page implemented with the code introduced so far can be viewed at the following URL.

https://kzjljm.csb.app/

Let's see if the validation actually takes place while the browser is idle!
By adding the following code, the results of the validation function execution will be output to the browser's console.

import { configureIdleTask } from "idle-task";

configureIdleTask({
  debug: true
});
Enter fullscreen mode Exit fullscreen mode

If you put text in the input area, you will see that validation is taking place during idle.

Console Log of validation

Measurements taken from the Performance tab of the Chrome Developer Tools show that functions are running while the browser is idle.

Measurements taken from the Performance tab of the Chrome Developer Tools

You can see the example in CodeSandbox.

Conclusion

I introduced how to validate form during browser idle by using idle-task .

https://github.com/hiroki0525/idle-task

This article will also help you to optimize your website.

https://dev.to/nuko_suke/improve-responsiveness-to-user-interactions-4a3p

If you found this helpful, please help someone else by sharing it or tagging someone in the comments!

Thanks!

Top comments (1)

Collapse
 
naucode profile image
Al - Naucode

Hey, that was a nice read, you got my follow, keep writing 😉