Oky, so wasted like 12 hours already on this. And I really need help.
I created a filter using an array via Map that returns some checkbox components
Component:
import { useEffect, useState } from "react"
interface Checkbox {
id: string | undefined,
name: string,
reg: any,
value: any,
label: string,
required?: boolean,
allChecked: boolean
}
const Checkbox = ({ id, name, reg, value, label, allChecked }: Checkbox) => {
const [checked, setChecked] = useState(false);
useEffect(() => {
setChecked(allChecked);
}, [allChecked])
return (
<>
<label key={id}>
<input type="checkbox"
{...reg}
id={id}
value={value}
name={name}
checked={checked}
onClick={() => {
setChecked(!checked)
}}
onChange={
() => { }
}
/>
{label}
</label>
</>
)
}
export default Checkbox;
Map:
dataValues.sort()
?
dataValues.map((e: any, i: number) => {
let slug = e.replace(' ', '-').toLowerCase();
return (
<div key={JSON.stringify(e)} id={JSON.stringify(e)}
>
<Checkbox id={slug}
name={title as string}
label={e as string}
value={e}
reg={{ ...register(title as string) }}
allChecked={allChecked}
/>
</div>
)
})
:
null
}
State that is just above the Map:
const [allChecked, setAllChecked] = useState<boolean>(false);
When I try to change the state on the parent and check or uncheck all of the checkboxes, nothing happens.
(the form works without a problem if I manually click on the checkboxes, but I cannot do this as I have some sections with over 40 values)
Sample of array:
dataValues = [
"Blugi",
"Bluza",
"Body",
"Bratara",
"Camasa",
"Cardigan",
"Ceas",
"Cercel",
"Colier",
"Fusta",
"Geanta Cross-body",
"Hanorac",
"Jacheta",
"Palton",
"Pantaloni",
"Pulover",
"Rochie",
"Rucsac",
"Sacou",
"Salopeta",
"Set-Accesorii",
"Top",
"Trench",
"Tricou",
"Vesta"
]
CodePudding user response:
allChecked
never changes (at least in the code shown here).
Here's the timeline:
The parent passes down a boolean prop
allChecked
. That's supposed to tell us if all the checkboxes are checked or not.useEffect
inCheckbox
runs on mount, andallChecked
isfalse
because that's its default.useEffect
then setschecked
toallChecked
's value,false
. Which it already is, because its default is alsofalse
.useEffect
then listens for a change inallChecked
via[allChecked]
that never comes.Clicking on any checkbox just toggles the state of that checkbox.
allChecked
's setter,setAllChecked
, is never passed to the child or called from the parent.
What's the solution?
Somewhere, setAllChecked(true)
needs to happen. Maybe a single checkbox with a label "Check all"?
Then, allChecked
in Checkbox
needs to be able to control the checkbox inputs. One implementation could be:
checked={checked || allChecked}
CodePudding user response:
I managed to solve this.
There were 2 main problems:
- Checkboxes were not rendering again so react-hook-form would see the old value, no matter what
- I couldn't press clear all multiple times, because I was sending the allChecked = = false info multiple times, and the state wasn't exactly changing.
What I did was force a render by integrating the allChecked state as an object
interface checkedState { checked: boolean, render: boolean }
So, whenever I send the state, I send it something like:
{
checked: true,
render: !allChecked.render
}
meaning that the new object is always new, no matter if I send the same information.