'CheckBox inside Formik form needs to be checked twice when a set state in handleChange is called
I've a Formik form with an array of checkBoxes that behave like radio buttons and a callback function:
function handleChange(
e: ChangeEvent<HTMLInputElement>,
arrayHelpers: FieldArrayRenderProps
) {
let us: IMUserSetting = {name:"db", value:e.target.id}
let c = !(userSettings.filter(x => x.name==="db" && x.value == us.value).length>0)
if (arrayHelpers.form.values.userSettings.length===0){
arrayHelpers.push(us);
}
else {
arrayHelpers.pop();
arrayHelpers.push(us);
}
setChanged(c);
/*
if (c) {
setTimeout(tSetChange,4000)
} else {
setTimeout(tUnSetChange,4000)
}
*/
}
when the call to "setChanged(c)" is not commented out, I need to click twice the checkBox to change selection, while after first click works correctly. I have spent a lot of time trying to figure out why this happens, tried to use even setTimeout to set state and noticed that after timeout expire the flag is restored back to the first checked checkbox. This is my first React work, probably I'm missing something on states.
I setted up a mock on codesandbox https://codesandbox.io/s/testformiktypescript-m9uik3?file=/src/userDb.tsx if You would like to try.
Have someone experienced something similar?
Thank You in advance.
Solution 1:[1]
The problem is the use of state for tracking isChanged:
const [changed, setChanged] = useState(false);
The reason this is a problem is that when you call setChanged you are updating state, triggering a rerender, and therefore accidently causing the Formik Form to reset to its initial values from currentDb. You only see this on the first click because once changed is true, setting it to true again the next time you click a checkbox won't cause another rerender.
You are using changed to decide whether to disable the ok button. I would recommend changing this to instead find out if anything has been changed from Formik using the dirty variable so that you avoid causing unintentional rerenders.
{({ isSubmitting, setSubmitting, values, setValues, dirty }) => (
Here's a codesandbox example of the solution!
You can then disable your button based on dirty, like this:
<Button
disabled={isSubmitting || !dirty}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Andrew Hulterstrom |
