React Hook Form 中的一个字段只有在该字段获得焦点时才会更新表单状态。

huangapple go评论72阅读模式
英文:

A field in a React Hook Form does not update the form state unless that field get the focus

问题

以下是翻译好的部分:

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

我正在使用React Hook 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:"

这是当我不点击“总计”字段时的情况:

"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:"

这是我的代码:

"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."

非常感谢大家的帮助。

英文:

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.

答案1

得分: 2

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 gets 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
英文:

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

import { useEffect } from &quot;react&quot;;
import { useForm } from &quot;react-hook-form&quot;
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(&quot;price&quot;) 
const quantity = watch(&quot;quantity&quot;)
useEffect( ()=&gt; {
setValue(&#39;total&#39;, price * quantity)
}, [price, quantity, setValue])
const onSubmit = data =&gt; console.log(data)
return (
&lt;div className=&quot;App&quot;&gt;
&lt;form onSubmit={handleSubmit(onSubmit)}&gt;
&lt;div&gt;
&lt;label htmlFor=&quot;quantity&quot;&gt;Quantity: &lt;/label&gt;
&lt;input type=&quot;number&quot; 
{...register(&quot;quantity&quot;)}  
/&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;label htmlFor=&quot;price&quot;&gt;Price: &lt;/label&gt;
&lt;input type=&quot;number&quot;
{...register(&quot;price&quot;)}
/&gt;
&lt;/div&gt;
{
/** &#39;total&#39; is the result of multiplying the two previous fields. 
*   It only updates the form data when it get the focus.
*/
}
&lt;div&gt;
&lt;label htmlFor=&quot;total&quot;&gt;Total: &lt;/label&gt;
&lt;input type=&quot;number&quot;
{...register(&quot;total&quot;)}
//value={watch(&#39;price&#39;) * watch(&#39;quantity&#39;)}
readOnly
/&gt;
&lt;/div&gt;
&lt;input type=&quot;submit&quot; value=&#39;Submit&#39; /&gt;
&lt;/form&gt;
&lt;/div&gt;
)
}
export default App

答案2

得分: 1

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


使用setValue 结合 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")} // 无需监听
readOnly
/>

英文:

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

const price = watch(&quot;price&quot;) 
const quantity = watch(&quot;quantity&quot;)

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(() =&gt; {
setValue(&#39;total&#39;, quantity * price)
}, [quantity, price])
...
&lt;input type=&quot;number&quot;
{...register(&quot;total&quot;)} // No need to watch        
readOnly
/&gt;

huangapple
  • 本文由 发表于 2023年2月18日 01:11:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/75487309.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定