skip to Main Content

I am using React Hook Form. I have this simple form:

A simple form

When I enter values in the "quantity "and "price" fields, the third field, "total" shows the result of multiplying them. So far, all fine. But I have noticed that when I click the submit button the value in the "total" field does not update the data form, unless that previously it get the focus by clicking on it.
This is what I get when I don’t click the "total" field:

Showing the state form in the console

As you can see in the last image, the value of the "total" field is not reflected in the form state.

This is my code:

import { useForm } from "react-hook-form"

function App() {

  const { register, handleSubmit, watch } = useForm({
    defaultValues: {
      price: 0,
      quantity: 0,
      total: 0
    }
  });

  const onSubmit = data => console.log(data)

  return (
    <div className="App">
      <form onSubmit={handleSubmit(onSubmit)}>

        <div>
          <label htmlFor="quantity">Quantity: </label>
          <input type="number" 
            {...register("quantity")}  
          />
        </div>

        <div>
          <label htmlFor="price">Price: </label>
          <input type="number"
            {...register("price")}
          />
        </div>
        
        {
          /** 'total' is the result of multiplying the two previous fields. 
          *   It only updates the form data when it get the focus.
          */
         }
        <div>
          <label htmlFor="total">Total: </label>
          <input type="number"
            {...register("total")}
            value={watch('price') * watch('quantity')}
            readOnly
          />
        </div>

        <input type="submit" value='Submit' />
      </form>
    </div>
  )
}

export default App

I was expecting the form state to update regardless of whether or not the "total" field got focus.

Thanks in advance everyone for your help.

2

Answers


  1. Chosen as BEST ANSWER

    Solved. Thank you @Anurag Srivastava (sorry I'm not allowed to vote yet). This is the final code:

    import { useEffect } from "react";
    import { useForm } from "react-hook-form"
    
    function App() {
    
      const { register, handleSubmit, setValue, watch } = useForm({
        defaultValues: {
          price: 0,
          quantity: 0,
          total: 0
        }
      });
    
      // I had to add these two lines
      const price = watch("price") 
      const quantity = watch("quantity")
    
      useEffect( ()=> {
        setValue('total', price * quantity)
      }, [price, quantity, setValue])
    
      const onSubmit = data => console.log(data)
    
      return (
        <div className="App">
          <form onSubmit={handleSubmit(onSubmit)}>
    
            <div>
              <label htmlFor="quantity">Quantity: </label>
              <input type="number" 
                {...register("quantity")}  
              />
            </div>
    
            <div>
              <label htmlFor="price">Price: </label>
              <input type="number"
                {...register("price")}
              />
            </div>
            
            {
              /** 'total' is the result of multiplying the two previous fields. 
              *   It only updates the form data when it get the focus.
              */
             }
            <div>
              <label htmlFor="total">Total: </label>
              <input type="number"
                {...register("total")}
                //value={watch('price') * watch('quantity')}
                readOnly
              />
            </div>
    
            <input type="submit" value='Submit' />
          </form>
        </div>
      )
    }
    
    export default App
    

  2. Edit: You would need to watch the fields as well, to get their values in the app:

    const price = watch("price") 
    const quantity = watch("quantity")
    

    It might be easier for you to use setValue combined with useEffect:

    const { register, handleSubmit, watch, setValue } = useForm({ 
      defaultValues: { price: 0, quantity: 0, total: 0 } 
    });
    
    ...
    
    useEffect(() => {
      setValue('total', quantity * price)
    }, [quantity, price])
    
    ...
    
      <input type="number"
        {...register("total")} // No need to watch        
        readOnly
      />
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search