The problem arises because the validate function in react-hook-form does not handle asynchronous operations well when combined with state updates from react-query. As a result, the hasErrors value does not get updated immediately due to the asynchronous nature of React state updates. To address this issue, we can use a useEffect hook to manage the form errors based on the react-query state.
import { useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { useQuery } from 'react-query'; import './index.css'; export function App() { const { register, setError, clearErrors, formState: { errors }, getValues, } = useForm({ mode: 'onChange', }); const { data, refetch, isError, isRefetchError, isLoadingError } = useQuery( 'repoData', () => fetch(getValues('example')).then((res) => res.json()), { enabled: false, refetchOnMount: false, refetchOnReconnect: false, refetchOnWindowFocus: false, retry: false, } ); const hasErrors = isError || isRefetchError || isLoadingError; const validate = async (value: string) => { if (value.length > 3) { await refetch(); // The validation function here does not return any validation result because errors are handled via useEffect return true; } return true; }; useEffect(() => { const value = getValues('example'); if (value && value.length > 3) { if (hasErrors) { setError('example', { type: 'manual', message: `Validation hasErrors value: ${JSON.stringify(hasErrors)}`, }); } else { clearErrors('example'); } } }, [hasErrors, setError, clearErrors, getValues]); return ( <> <h1>Input Validation Bug</h1> <form> <input defaultValue="https://jsonplaceholder.typicode.com/todos/1" {...register('example', { validate })} placeholder="Enter any public API URL" /> {errors.example && <p>{errors.example?.message}</p>} <span> Actual hasErrors value: <b>{JSON.stringify(hasErrors)}</b> </span> </form> <pre>{JSON.stringify(data, null, 2)}</pre> </> ); }