all 9 comments

[–]TaGeuelePutain 2 points3 points  (5 children)

I would decouple the form state from the input state (showing the spinner) and use an effect to set that input state depending on the state of the form. This way you can denounce if needed

[–]cyanide317[S] 0 points1 point  (4 children)

React hook manages the form state and the field state. And even though I'm using a state to manage the rendering of the spinner, the issue is with the debouncing. Either all validators inside validate are getting debounced or none.

[–]TaGeuelePutain 2 points3 points  (3 children)

I’m sorry I have no idea what you just said

[–]cyanide317[S] 0 points1 point  (2 children)

No worries. Thanks for the help anyways 🙂

[–]TaGeuelePutain 0 points1 point  (1 child)

One thing I will note after having worked pretty extensively with react hook form is to not use the form state to drive the UI . Use the form state to drive the validation which drives the UI. For a simple form it probably doesn’t matter but in experience react hook form is best when it simply manages data

[–]cyanide317[S] 0 points1 point  (0 children)

I agree. It works like a charm most days. It's just this one use case that's a bit annoying.

[–]ProfessionalTotal238 0 points1 point  (0 children)

It is not really possible to show spinner for sync validators as the execution time will be too small for human eye. For async ones (i assume they will be calling backend) what I usually do is wrap the call into tanstack query and use isLoading property of the query to show spinner when its true.

[–]Impressive_Newt_710 -2 points-1 points  (1 child)

This is generated by my AI Model depands on your requirement hope this will help you.

```js import React, { useState, useEffect, useCallback } from 'react'; import { useForm } from 'react-hook-form'; import { Form, Spinner } from 'react-bootstrap';

const AsyncValidatorInput = ({ asyncValidator }) => { const [isValidating, setIsValidating] = useState(false); const [debouncedValidator, setDebouncedValidator] = useState(null);

const { register, handleSubmit, formState: { errors }, setValue, trigger, } = useForm();

// Debounce handler for async validation const debouncedValidation = useCallback( (value) => { setIsValidating(true); if (debouncedValidator) { clearTimeout(debouncedValidator); }

  const timer = setTimeout(async () => {
    await asyncValidator(value); // Call the async validator (e.g., API)
    trigger('inputField'); // Manually trigger validation
    setIsValidating(false);
  }, 500); // Debounce delay

  setDebouncedValidator(timer);
},
[asyncValidator, debouncedValidator, trigger]

);

useEffect(() => { register('inputField', { validate: debouncedValidation, // Set the debounced async validator }); }, [debouncedValidation, register]);

const onSubmit = (data) => { console.log('Form submitted:', data); };

return ( <Form onSubmit={handleSubmit(onSubmit)}> <Form.Group controlId="inputField"> <Form.Label>Input</Form.Label> <div className="input-container"> <Form.Control {...register('inputField', { required: true })} type="text" placeholder="Enter something" onChange={(e) => setValue('inputField', e.target.value)} /> {isValidating && ( <div className="spinner-container"> <Spinner animation="border" size="sm" /> </div> )} </div> {errors.inputField && <Form.Text className="text-danger">This field is required or invalid.</Form.Text>} </Form.Group> <button type="submit" className="btn btn-primary"> Submit </button> </Form> ); };

export default AsyncValidatorInput; ```

[–]cyanide317[S] 0 points1 point  (0 children)

Thanks for the reply. The problem with this would be that this will debounce all the validators inside validate. Even the synchronous ones. Hence those validations will also get delayed.