Consider the following code, there are multiple checkboxes whose fields are:
<Checkbox
checked={checked[element]}
onChange={(e) => {
setChecked({ ...checked, [e.target.name]: !checked[e.target.name] });
}}
name={element}
/>
Now consider a button used to check all the checkboxes:
<Button
variant="contained"
onClick={() => {
setIsAllChecked(!isAllChecked);
Object.keys(checked).forEach((e) => {
setChecked({ ...checked, [e]: !checked[e] });
});
}}
marginRight={2}
sx={{ margin: '2rem' }}
>
{isAllChecked ? 'Unselect All' : 'Select All'}
</Button>
the onCLick
logic renders through an array of all elements, and is supposed to set their value to true, but for some reason its only setting the value of the last checkbox as true. here is the checked
state variable for your reference:
const [checked, setChecked] = useState({
'Add Employee Importer': false,
'Employee LOP': false,
'LOP Reversal Importer': false,
'Employee Bank Details': false,
'Employee Loan Details': false,
'Employee Category': false,
'Employee Resignation': false,
'Bulk Salary Information Of Employees': false,
'Basic Employee Information': false,
'Employee PF_ESI Details': false,
'Final Settlement Details': false,
'Add revised salary': false
});
CodePudding user response:
The issue is your loop here
Object.keys(checked).forEach((e) => {
setChecked({ ...checked, [e]: !checked[e] });
});
setChecked is an asynchronous call. That is, your checked state wont change until the next render. When you set one state's value to true
, the next call will set it back to false
, and its current key value to true. It will repeat that until you are at your last element. Hence, why only the last checkbox is true
.
For example, consider this state
const [checked, setChecked] = useState({a : false, b: false})
Now consider this.
setChecked({ ...checked, a: true})
console.log(checked) // returns { a: false, b: false}
setChecked({ ...checked, b: true})
The second setChecked
call overwrites the first call due to the ...checked
, and since checked states has not changed due to the async nature, checked would only set key b
to true
Instead for your code, you should make a copy of checked
to do this.
const checkedCopy = { ...checked }
Object.keys(checkedCopy).forEach((e) => {
checkedCopy.e = !checkedCopy.e;
});
setChecked(checkedCopy)
With this, you now only have 1 setChecked
call.