My parent component contains an array of categories. The component renders a list, and each list item has a checkbox, which is a child component.
I use useState() for the checkedCategories array, and for the checked/unchecked state of the the child component Checkbox.
There is one detail left: when the "clear all" button is clicked, all the checkboxes should be unchecked. So I have to manipulate the checked state of all the Checkbox children somehow.
Parent component:
import {useState, useEffect} from "react";
import Checkbox from "../functions/Checkbox.js";
function CategoryList() {
const categories = ['CategoryA','CategoryB', 'CategoryC']
const [checkedCategories, setCheckedCategories] = useState([]);
const addToCheckedCategories = id => {
const updatedCheckedCategories = [...checkedCategories];
updatedCheckedCategories.push(id);
setCheckedCategories(updatedCheckedCategories);
};
const removeFromCheckedCategories = id => {
const updatedCheckedCategories = checkedCategories.filter(cat => cat !== id);
setCheckedCategories(updatedCheckedCategories);
};
const removeFilters = () => {
//????
}
useEffect(() => {
console.log('checked categories updated');
console.log(checkedCategories);
if (!checkedCategories.length) {
console.log('the array is empty');
//Set all the checkboxes' checked state to "false" somehow...?
}
}, [checkedCategories]);
return(
<div>
<ul>
{categories.map(categories =>
<li key={categories.toLowerCase()}>
<Checkbox id={categories.toLowerCase()}
label={categories}
addToCheckedCategories={addToCheckedCategories}
removeFromCheckedCategories={removeFromCheckedCategories}
/>
</li>
)}
</ul>
<button onClick={removeFilters}>Clear all</button>
</div>
)
}
export default CategoryList;
Child component:
import { useState } from 'react';
function Checkbox({id, label, addToCheckedCategories, removeFromCheckedCategories}) {
const [checked, setChecked] = useState(false);
const handleChange = id => {
if (checked) {
removeFromCheckedCategories(id);
console.log('removed ' + id);
} else {
addToCheckedCategories(id);
console.log('added ' + id);
}
setChecked(!checked);
console.log('changed value of checkbox');
}
return(
<label htmlFor={id} >
<input type="checkbox"
name="category-input"
id={id}
onChange={handleChange}
/>
{label}
</label>
);
}
export default Checkbox;
I would lift the state completely to the parent making the Checkbox
component stateless:
function Checkbox({
id,
label,
checked,
addToCheckedCategories,
removeFromCheckedCategories,
}) {
const toggle = () => {
if (checked) {
removeFromCheckedCategories(id);
} else {
addToCheckedCategories(id);
}
};
return (
<label htmlFor={id}>
<input
type="checkbox"
name="category-input"
id={id}
onChange={() => toggle()}
checked={checked}
/>
{label}
</label>
);
}
From your parent you can pass down the checked
property simply checking if that category is present in the checkedCategories
array.
function CategoryList() {
const categories = ['CategoryA', 'CategoryB', 'CategoryC'];
const [checkedCategories, setCheckedCategories] = useState([]);
const addToCheckedCategories = (id) => {
const updatedCheckedCategories = [...checkedCategories];
updatedCheckedCategories.push(id);
setCheckedCategories(updatedCheckedCategories);
};
const removeFromCheckedCategories = (id) => {
const updatedCheckedCategories = checkedCategories.filter(
(cat) => cat !== id
);
setCheckedCategories(updatedCheckedCategories);
};
// Remove filters is as easy as setting an empty array
const removeFilters = () => {
setCheckedCategories([]);
};
useEffect(() => {
console.log('checked categories updated');
console.log(checkedCategories);
}, [checkedCategories]);
return (
<div>
<ul>
{categories.map((category) => (
<li key={category.toLowerCase()}>
<Checkbox
id={category.toLowerCase()}
label={category}
checked={checkedCategories.includes(category.toLowerCase())}
addToCheckedCategories={addToCheckedCategories}
removeFromCheckedCategories={removeFromCheckedCategories}
/>
</li>
))}
</ul>
<button onClick={removeFilters}>Clear all</button>
</div>
);
}
Using this approach clearing all is very easy, all you have to do is setting the checkedCategories
array to an empty one.
Demo: https://stackblitz.com/edit/react-pwxgaq?file=src%2FApp.js