通过回调和挂钩(useState、useEffect)从父级的 onClick 事件更改 React 子组件的状态

Change React child component's state from an onClick event in parent, with callbacks and hooks (useState, useEffect)

我的父组件包含一组类别。该组件渲染一个列表,每个列表项都有一个复选框,它是一个子组件。

我对 checkedCategories 数组和子组件 Checkbox 的 checked/unchecked 状态使用 useState()。

还有一个细节:单击“全部清除”按钮时,应取消选中所有复选框。所以我必须以某种方式操纵所有 Checkbox 子项的选中状态。

父组件:

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;

子组件:

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;

我会将状态完全提升到 parent 使 Checkbox 组件无状态:

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>
  );
}

从您的 parent 您可以传递 checked 属性 只需检查 checkedCategories 数组中是否存在该类别。

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>
  );
}

使用这种方法清除所有内容非常简单,您所要做的就是将 checkedCategories 数组设置为空数组。

演示:https://stackblitz.com/edit/react-pwxgaq?file=src%2FApp.js