skip to Main Content

I have a toggle button to turn auto mode on and off, but I don’t know how to make react-hook-form automatically submit when this button is turned on.
I have tried document.querySelector('form').requestSubmit() but it didn’t work.
Is there a way for them to automatically submit each time progress is completed plus with 3 seconds?

  const [progress, setProgress] = useState(null)
  const [autoMode, setAutoMode] = useState(false) // Use state for auto mode
  const [autoInterval, setAutoInterval] = useState(null) // Use state for interval

  const {
    register,
    handleSubmit,
    formState: { isSubmitting }
  } = useForm()

  // Calculate interval based on start_time, end_time, and an extra 3 seconds
  const calculateInterval = (startTimeStr, endTimeStr) => {
    const startTime = new Date(startTimeStr).getTime() // Convert to timestamp
    const endTime = new Date(endTimeStr).getTime() // Convert to timestamp
    const duration = endTime - startTime // Duration in milliseconds
    const extraTime = 3000 // Add 3 seconds (3000 ms)
    return duration + extraTime // Total interval duration
  }

  // Auto mode toggle logic
  const handleAutoMode = () => {
    if (!autoMode && progress) {
      startAutoRefinement(progress.start_time, progress.end_time)
    } else {
      stopAutoRefinement()
    }
    setAutoMode(!autoMode) // Toggle auto mode
  }

  // Start auto mode with dynamic interval
  const startAutoRefinement = (startTime, endTime) => {
    const intervalDuration = calculateInterval(startTime, endTime)
    const interval = setInterval(() => {
      document.querySelector('form').requestSubmit() // Automatically submits the form
    }, intervalDuration)

    setAutoInterval(interval) // Store interval in state
  }

  // Stop auto mode and clear the interval
  const stopAutoRefinement = () => {
    if (autoInterval !== null) {
      clearInterval(autoInterval)
      setAutoInterval(null)
    }
  }
useEffect(() => {
    return () => stopAutoRefinement() // Clean up when the component unmounts
  }, [])

  const onSubmit = async (data) => {
    if (!data.elixir) {
      Swal.fire({
        icon: 'error',
        title: 'Lỗi',
        text: 'Vui lòng chọn đan dược để luyện!',
        showConfirmButton: false,
        timer: 1500
      })
      return
    }

    const formData = new FormData()
    formData.append('elixir_id', parseInt(data.elixir))

    const res = await AlchemyService.createElixir(formData)
    if (res.status === 201) {
      Swal.fire({
        icon: 'success',
        title: 'Thành công',
        text: `Luyện thành công`,
        showConfirmButton: false,
        timer: 1500
      })
    } else {
      Swal.fire({
        icon: 'error',
        title: 'Thất bại',
        text: res.response?.data[0] || 'Luyện thất bại',
        showConfirmButton: false,
        timer: 1500
      })
    }
  }

Below is the form

<form onSubmit={handleSubmit(onSubmit)} className='flex flex-col gap-3 font-medium text-gray-600'>
      {list.map((item, index) => (
        <div key={index} className='flex flex-col gap-1'>
          <div className='flex items-center gap-1'>
            <input type='radio' {...register('elixir')} value={item.elixir.id} id={`dan-duoc-${index}`} />
            <label htmlFor={`dan-duoc-${index}`} className='font-medium text-yellow-600'>
              {' '}
              <span>{item.elixir.name}</span> (độ thành thục: {item.proficiency} %)
            </label>
          </div>
          <p className='text-sm text-gray-600'>
            <i>
              <span className='font-bold text-gray-700'>Đan dược này cần:</span> {item.description}
            </i>
          </p>
          <p className='text-sm text-gray-600'>
            Thời gian luyện: <b>{Math.ceil(parseInt(item.elixir.crafting_time) / 60)}</b> giờ
          </p>
        </div>
      ))}

      <button
        type='button'
        onClick={handleAutoMode}
        className={`px-2 py-1 ${autoMode ? 'bg-red-500' : 'bg-primary'} text-white font-medium rounded w-fit`}
      >
        {autoMode ? 'Tắt auto luyện đan' : 'Bật auto luyện đan'}
      </button>

      {progress === null ? (
        isSubmitting ? (
          <p>Đang tải...</p>
        ) : (
          <div className='w-full flex justify-center items-center mt-10'>
            <button type='submit' className='size-60'>
              <img src={Furnace} alt='' className='size-full object-contain' />
            </button>
          </div>
        )
      ) : (
        <AlchemyProgressBar
          startTimeStr={progress.start_time}
          endTimeStr={progress.end_time}
          name={progress.elixir_name}
          setProgressData={setProgress}
        />
      )}
    </form>

2

Answers


  1. Just useRef to get a hand on the <form> Element, and call its .submit() method:

    const formRef = useRef(null);
    
    // When the form should be automatically submitted
    formRef.current.submit();
    
    // Pass the formRef to the `ref` prop of `<form>`
    // so that React associates it with the DOM Element
    <form ref={formRef} /* other props */>
    
    Login or Signup to reply.
  2. The answer above is correct. I just want to add this one as well. Because you using react-hook-form and have access to handleSubmit, you can just manually called that method like this

    const startAutoRefinement = (startTime, endTime) => {
        const intervalDuration = calculateInterval(startTime, endTime)
        const interval = setInterval(() => {
          handleSubmit(onSubmit)(); // calling handleSubmit here
        }, intervalDuration)
    
        setAutoInterval(interval) // Store interval in state
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search