For a registered input, I failed to update it using my own custom hook. In my sample codes as shown below, the result2 didn't set to "bar" when the button was clicked, although r2 was updated correctly.
import { useForm } from "react-hook-form";
import { useBar } from "./useBar";
function App() {
const { register, setValue } = useForm({
defaultValues: { result1: "foo", result2: "foo" },
});
const [r2, setBar] = useBar("foo");
const showResults = () => {
setValue("result1", "bar");
setBar();
setValue("result2", r2);
};
return (
<div>
<button onClick={showResults}>Show results</button>
<form>
<div>
<label>Result 1</label>
<input type="text" {...register("result1")} />
</div>
<div>
<label>Result 2</label>
<input type="text" {...register("result2")} />
</div>
<div>
<label>R 2</label>
<input type="text" value={r2} />
</div>
</form>
</div>
);
}
export default App;
My useBar hook:
import { useState } from "react";
export const useBar = (initialValue = "") => {
const [state, setState] = useState(initialValue);
const setBar = () => {
setState("bar");
};
return [state, setBar];
};
What is the proper way to change result2 value using setBar? Kindly advise.
2024-03-30 Edit: Thanks for the answer which explained the cause of the problem and the useEffect workaround. However I wish there is a more elegant solution, by getting rid of r2 which serve no purpose other than an intermediate variable.
Any idea?
The asynchronous nature of state updates in React seems to be causing this. When you call setBar() to update r2, the state update isn't immediate, and r2 doesn't reflect the new value of "bar" immediately after setBar() is called. So, when you immediately call setValue("result2", r2), r2 still holding its previous value ("foo") imo. you can try to use useEffect to update the value of "result2" after r2 has been updated. Try something like this,