Parent 组件在 children 组件列表上调用 child 组件函数

Parent component to call child component function on a list of children component

这就是我现在拥有的。

除重置按钮外的每一行都是一个名为 Item 的 child 组件。一个项目有一个指示其计数的徽章,2 个用于递增、递减的按钮和一个 delete 按钮。名为 ItemList 的 parent 组件包含重置按钮和 children。由于 parent 维护 children 列表,因此删除功能也在 parent 中实现。除了 reset 按钮外,我需要的所有功能都已完成。

重置按钮可以被认为是一个主按钮,点击后应该能够重置所有 children 的 count。计数由每个 child 保持为状态,因此理想情况下 parent 应该调用它包含在列表中的每个 child 的重置函数,但我无法为此提供代码特定部分。我不确定如何访问每个 child 的重置功能并将其应用于列表中的所有 children。

项目代码 (child)

function Item({ deleteHandler }) {
  const [count, setCount] = useState(0);
  const [cName, setCName] = useState("badge bg-warning text-dark");

  useEffect(() => {
    setCName(count !== 0 ? "badge bg-primary" : "badge bg-warning text-dark");
  }, [count]);

  const increment = () => {
    setCount((prevCount) => prevCount + 1);
  };

  const decrement = () => {
    setCount((prevCount) => prevCount - 1);
  };
  
  //this is what needs to be called
  const reset = () => {
    setCount(0);
  };

  const zero = "zero";

  return (
    <div style={{ marginTop: "10px" }}>
      <span style={{ marginRight: "10px" }} className={cName}>
        {count !== 0 ? count : zero}
      </span>
      <button
        style={{ marginRight: "5px" }}
        className="btn btn-secondary btn-sm"
        onClick={increment}
      >
        +
      </button>
      <button
        style={{ marginRight: "5px" }}
        className="btn btn-secondary btn-sm"
        onClick={decrement}
      >
        -
      </button>
      <button onClick={deleteHandler} className="btn btn-danger btn-sm">
        Delete
      </button>
    </div>
  );
}

export default Item;

项目列表代码 (parent)

function ItemList() {
  const [items, setItems] = useState([Item, Item, Item]);

  const deleteItem = (index) => {
    alert(index);
    var temp = [...items]; //create new copy
    temp.splice(index, 1);
    setItems(temp);
  };

  const resetAll = () => {
    //this is where I need to call reset() on all the items (children)
  };

  return (
    <div>
      <div style={{ marginTop: "10px" }}>
        <button className="btn btn-primary" onClick={resetAll}>
          Reset
        </button>
        {items.map((MyItem, index) => {
          return (
            <div key={index}>
              <MyItem deleteHandler={() => deleteItem(index)} />
            </div>
          );
        })}
      </div>
    </div>
  );
}

export default ItemList;

虽然您可以创建一个 React ref 并将它们转发给每个子组件,并实现 useImperativeHandle 挂钩,但这应该只是最后的手段。您可能会发现此 Fully uncontrolled component with a key 模式很有用。

它使用 React 键来重置组件,这实际上是 unmounts/mounts 一个新的“实例”。

添加一个额外的状态来保存 key 值,并在 resetAll 处理程序中更新此状态。我使用了一个随机值,但任何 GUID 生成器甚至一个简单的递增计数器都可以工作,关键部分是使用了新的 React 键值。

function ItemList() {
  const [items, setItems] = useState([Item, Item, Item]);
  const [key, setKey] = useState(Math.random()); // <-- key state

  const deleteItem = (index) => {
    alert(index);
    var temp = [...items]; //create new copy
    temp.splice(index, 1);
    setItems(temp);
  };

  const resetAll = () => {
    setKey(Math.random()); // <-- update key state
  };

  return (
    <div>
      <div key={key} style={{ marginTop: "10px" }}> // <-- resets elements/components
        <button className="btn btn-primary" onClick={resetAll}>
          Reset
        </button>
        {items.map((MyItem, index) => {
          return (
            <div key={index}>
              <MyItem deleteHandler={() => deleteItem(index)} />
            </div>
          );
        })}
      </div>
    </div>
  );
}