Home > Enterprise >  Populate array in parent based on checked inputs in child component via React hooks / functional com
Populate array in parent based on checked inputs in child component via React hooks / functional com

Time:04-28

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!

  • Related