I have a parent component that renders a list of categories. Each list item contains a child component, Checkbox, which contain a checkbox input.
In the parent component, I need an array containing the ID's of the checkbox inputs that are checked. If a checkbox is unchecked, the ID should be removed from the array.
In the Checkbox component, the handleChange
function works, but I also need to send the data to the parent somehow. I need some kind of callback function for this, I guess?
How can I access the ID's of the checked inputs in the parent component?
My code so far:
Parent component:
import {useState} from "react";
import Checkbox from "../functions/Checkbox.js";
function CategoryList() {
const categories = ['CategoryA','CategoryB', 'CategoryC']
const [checkedCategories, setCheckedCategories] = useState([]);
return(
<ul>
{categories.map(categories =>
<li key={categories.toLowerCase()}>
<Checkbox id={categories.toLowerCase()}
label={categories}
/>
</li>
)}
</ul>
)
}
export default CategoryList;
Child component:
function Checkbox(props) {
const [checked, setChecked] = useState(false);
const checkboxId = props.id;
const checkboxLabel = props.label;
const handleChange = () => {
setChecked(!checked);
console.log('changed value of checkbox');
}
return(
<label htmlFor={checkboxId} >
<input type="checkbox"
name="category-input"
id={checkboxId}
onChange={handleChange}
/>
{checkboxLabel}
</label>
);
}
export default Checkbox;
CodePudding user response:
function CategoryList() {
const categories = ["CategoryA", "CategoryB", "CategoryC"];
const [checkedCategories, setCheckedCategories] = useState([]);
const checkboxChanged = (id) => {
console.log(id);
};
return (
<ol>
{categories.map((categories) => (
<li key={categories.toLowerCase()}>
<Checkbox
id={categories.toLowerCase()}
label={categories}
checkboxChanged={checkboxChanged}
/>
</li>
))}
</ol>
);
}
props.checkboxChanged will send id of checkbox to parent component which was changed
function Checkbox(props) {
const [checked, setChecked] = useState(false);
const checkboxId = props.id;
const checkboxLabel = props.label;
const handleChange = () => {
setChecked(!checked);
console.log("changed value of checkbox");
props.checkboxChanged(checkboxId); // will send id back to parent component
};
return (
<label htmlFor={checkboxId}>
<input
type="checkbox"
name="category-input"
id={checkboxId}
onChange={handleChange}
/>
{checkboxLabel}
</label>
);
}
CodePudding user response:
I think for this case you need to manipulate objects and not just strings, since you will be storing both a label
and a checked
value.
The following code fits better
import React, { useEffect, useState } from 'react';
import Checkbox from "../functions/Checkbox.js";
function CategoryList() {
const categories = [{ label: 'CategoryA', checked: false }, { label: 'CategoryB', checked: false }, { label: 'CategoryC', checked: false }];
const [checkedCategories, setCheckedCategories] = useState([]);
// Keeps your array of selected categories constantly updated
useEffect(() => {
const categoriesFilter = categories.filter(category => category.checked);
setCheckedCategories(categoriesFilter);
}, [categories]);
return (
<ol>
{categories.map(category =>
<li key={category.label.toLowerCase()}>
<Checkbox id={category.label.toLowerCase()} data={category} />
</li>
)}
</ol>
)
}
export default AllBots();
function Checkbox({ id: checkboxId, data: category }) {
return (
<label htmlFor={checkboxId} >
<input type="checkbox"
name="category-input"
id={checkboxId}
onChange={() => category.checked = !category.checked}
/>
{category.label}
</label>
);
}
export default Checkbox;
CodePudding user response:
I think you can just pass the functions to update your checked categories. Using the lowercase version of your id, it should be something like this:
Parent component:
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);
};
return(
<ul>
{categories.map(categories =>
<li key={categories.toLowerCase()}>
<Checkbox id={categories.toLowerCase()}
label={categories}
addToCheckedCategories={addToCheckedCategories}
removeFromCheckedCategories={removeFromCheckedCategories}
/>
</li>
)}
</ul>
);
}
Child component:
function Checkbox(props) {
const [checked, setChecked] = useState(false);
const checkboxId = props.id;
const checkboxLabel = props.label;
const addToCheckedCategories = props.addToCheckedCategories;
const removeFromCheckedCategories = props.removeFromCheckedCategories;
const handleChange = id => {
if (checked) {
removeFromCheckedCategories(id);
} else {
addToCheckedCategories(id);
}
setChecked(!checked);
console.log('changed value of checkbox');
}
return(
<label htmlFor={checkboxId} >
<input type="checkbox"
name="category-input"
id={checkboxId}
onChange={() => handleChange(checkboxId)}
/>
{checkboxLabel}
</label>
);
}
export default Checkbox;
Let me know if it helps!