Search code examples
reactjsreact-hookscallbackuse-statereact-functional-component

Populate array in parent based on checked inputs in child component via React hooks / functional components


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;

Solution

  • 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!