I am trying to have a list of components where each one takes user input and have a separate state. I want then to be able to filter this list and get the components where for example "switch" is true. I have tried many things but it seems I am not able to figure out how to do this. Lastly I did this:
My parent component
export const Parking = () => {
const [position, setPosition] = useState([false,false,false])
const onBayClick = (index) => {
position[index-1] === false? setPosition([...position.slice(0, index) , true, ...position.slice(index + 1)]):setPosition([...position, false])
}
const myBays = []
for (let i = 1; i < 4; i++) {
myBays.push(<BayForm key = {i} child = {i} state = {position[i]} onClick = {onBayClick}/>)
}
const [filteredBays, setFilteredBays] = useState(myBays)
const filterBays = () => {
setFilteredBays(myBays.filter(bay => {
return bay.position === false
}))
}
return (
<>
{myBays}
</>
)
}
My child component. I am only posting the relevant bits as it is too long.
const handleClick = () => {
onClick(index)
}
<FormGroup>
<FormControlLabel control={<Switch checked = {state} onChange = {handleClick} color = 'warning'/>} label="Switch" />
</FormGroup>
But when I try to flick the switch, I get the following error:
"Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components%s"
What is the correct way of doing this? I get errors whatever I try.
Well, i suspect you indeed pass the undefined value from Parking
down to the Switch
right here:
for (let i = 1; i < 4; i++) {
myBays.push(<BayForm key = {i} child = {i} state = {position[i]} onClick = {onBayClick}/>)
}
Your populated array position[i]
has 3 values, hence valid indexes are 0, 1 and 2.
So set it to:
for (let i = 0; i < position.length; i++)
If you need to render this index in your BayForm
, just add 1
to it there
Also see the problem here:
const onBayClick = (index) => {
position[index-1] === false
? setPosition([...position.slice(0, index) , true, ...position.slice(index + 1)])
: setPosition([...position, false])
}
This line setPosition([...position, false])
means get existing array, copy it and combine it with false, which causes the array to grow every time.
For changing one value in the array in immutable way i suggest to use map function:
const onBayClick = (bayIndex) => {
setPosition(previousPositions => previousPositions.map((it, index) => { // iterating through the array
if (index === bayIndex) { // if the clicked index matches this one we iterate
return !it // just set it's opposite value
}
return it // otherwise keep it as it is
}))
}