【问题标题】:Parent component to call child component function on a list of children component父组件在子组件列表上调用子组件函数
【发布时间】:2021-10-17 13:22:15
【问题描述】:

这就是我现在拥有的。

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

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

项目代码(子项)

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;

ItemList(父级)的代码

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;

【问题讨论】:

标签: javascript reactjs components


【解决方案1】:

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

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

添加一个额外的状态来保存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>
  );
}

【讨论】:

  • 这是一个非常巧妙的解决方案,我什至不需要依靠孩子来重置。我知道裁判可以完成这项工作,但不想使用这种糟糕的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-25
  • 2019-11-27
  • 2018-07-01
  • 1970-01-01
相关资源
最近更新 更多