如何在React中从父组件调用子组件的方法?

3

在父组件中有一组React组件。在父组件的某个事件中,我想遍历子组件数组,并为每个组件调用一个方法。如何实现呢?似乎不能像在纯JS中那样仅仅通过类实例来调用方法。以下是简化后的代码:

const Item = props => {
  const value = () => 'result!';
  return (
        <div></div>
  )
}
 
const App = props => {
  const items = props.items.map(item => <Item key={uuid()} item={item} />)
  const run = e => {
    items.map(item => console.log(item.value()))
  }
  return (
    <button onClick={run} type="button">Run!</button>
  ) 
}

const items = [
  'Lorem ipsum dolor sit amet',
  'consectetur adipiscing elit'
];

ReactDOM.render(<App items={items} />, document.querySelector("#app"))


我已创建一个包含此代码的jsfiddle-https://jsfiddle.net/jkLq26pg/37/。 在第11行调用了方法value()并引发了一个错误。但是记录item.props有效,并且为每个项输出道具。为什么方法没有被调用? 请给我提供一个建议,如何使它工作。

你试图像调用类方法一样调用 value,即 item.value(),但它并不是一个类方法。你正在编写普通函数,因此 value 仅在你的 Item 函数内可用。 - jmargolisvt
你可以使用 ref:https://reactjs.org/docs/refs-and-the-dom.html#adding-a-ref-to-a-class-component。但是建议尽可能避免使用它。因此,更好的问题是为什么你想要它,是否有一种方法可以避免它并通过 props 解决问题。如果你想要值,则子组件应该接受一个 onChange prop 来传递更改后的值,然后父组件保持值的状态。 - Marko Gresak
items将包含RENDERED ITEM组件的列表。 - pramod singh
2个回答

3

在您的情况下,您需要遍历数组并使用回调引用附加一个ref。使用forwardRef呈现子组件,并使用useImperativeHandle钩子将您的函数公开给父组件。

演示代码

代码片段

const Item = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
    value: () => "result!"
  }));

  return <div ref={ref} />;
});

const itemsz = ["Lorem ipsum dolor sit amet", "consectetur adipiscing elit"];
const App = props => {
  const ref = useRef({});

  const items = itemsz.map((item, index) => {
    return (
      <Item
        ref={r => (ref.current[index] = r)}
        key={index}
        item={item}
      />
    );
  });
  const run = e => {
    items.map((item, index) => console.log(ref.current[index].value()));
  };
  return (
    <>
      <h3>click run and see console log</h3>
      <button onClick={run} type="button">
        Run!
      </button>
      {items}
    </>
  );
};

注意 - 尽量避免使用这种模式。


谢谢您的回复。我认为使用refs会使代码变得更加复杂。我想知道为什么要这样实现。无论如何,我得到了一个建议,将状态从子组件移动到父组件并存储它。这似乎很奇怪,但更容易理解。我打算先尝试这种方法。 - Anton Grigoryev

0
解决这个问题的一种方法是编写 useEffect 并在其中调用您的 item.value() 逻辑。然后,一旦您的列表已经挂载到 DOM 上,您的函数将自动被调用。这可能是调用您的函数的正确位置,因为您的列表已经呈现在 DOM 中,副作用可以得到处理。
const Item = props => {
  const value = () => 'result!';

  // Handle your side effects here
  useEffect(() => {
    value();
  }, []);

  return (
        <div></div>
  )
}

这个 useEffect 将在组件挂载到 DOM 节点后起作用。您可以始终将函数放置在基于类的组件中的生命周期方法或功能组件中的钩子中,并根据情况从那里调用它们。


谢谢,但这不起作用,因为我需要在子组件已经挂载和渲染后运行其方法。并且它甚至可以在父事件中多次运行。 - Anton Grigoryev
如果你希望在按钮点击时处理它,那么你可以在按钮点击时切换状态,并将该状态作为prop传递给子组件,并将其作为useEffect的依赖项添加。或者使用componentDidUpdate来比较子组件中的状态更改并在此之后触发函数。 - Hassaan Tauqir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接