我有两个组成部分:

父组件 子组件

我试图从Parent调用Child的方法,我尝试了这种方式,但不能得到一个结果:

class Parent extends Component {
  render() {
    return (
      <Child>
        <button onClick={Child.getAlert()}>Click</button>
      </Child>
      );
    }
  }

class Child extends Component {
  getAlert() {
    alert('clicked');
  }
 
  render() {
    return (
      <h1 ref="hello">Hello</h1>
    );
  }
}

是否有一种方法从父调用子方法?

注意:子组件和父组件在两个不同的文件中。


当前回答

我希望我没有重复上面的内容但是如果传递一个回调道具来设置父类中的函数呢?这很有效,也很简单。(添加的代码在////之间)

class Parent extends Component {
  ///// 
  getAlert = () => {} // initial value for getAlert

  setGetAlertMethod = (newMethod) => {
    this.getAlert = newMethod;
  }
  /////

  render() {
    return (
      <Child setGetAlertMethod={this.setGetAlertMethod}>
        <button onClick={this.getAlert}>Click</button>
      </Child>
      );
    }
  }



class Child extends Component {
  /////
  componentDidMount() {
    this.props.setGetAlertMethod(this.getAlert);
  }
  /////

  getAlert() => {
    alert('clicked');
  }

  render() {
    return (
      <h1 ref="hello">Hello</h1>
    );
  }
}

其他回答

首先,让我声明一下,在React领域,这通常不是做事的方式。通常,您要做的是将功能传递给道具中的子元素,并在事件中传递子元素的通知(或者更好的方法是:分派)。

但如果必须在子组件上公开命令式方法,则可以使用refs。记住,这是一个逃生口,通常表明有更好的设计可用。

以前,引用只支持基于类的组件。 随着React Hooks的出现,这种情况不再存在

Modern React with Hooks (v16.8+)

const { forwardRef, useRef, useImperativeHandle } = React; // We need to wrap component in `forwardRef` in order to gain // access to the ref object that is assigned using the `ref` prop. // This ref is passed as the second parameter to the function component. const Child = forwardRef((props, ref) => { // The component instance will be extended // with whatever you return from the callback passed // as the second argument useImperativeHandle(ref, () => ({ getAlert() { alert("getAlert from Child"); } })); return <h1>Hi</h1>; }); const Parent = () => { // In order to gain access to the child component instance, // you need to assign it to a `ref`, so we call `useRef()` to get one const childRef = useRef(); return ( <div> <Child ref={childRef} /> <button onClick={() => childRef.current.getAlert()}>Click</button> </div> ); }; ReactDOM.render( <Parent />, document.getElementById('root') ); <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <div id="root"></div>

useImperativeHandle()的文档在这里:

useImperativeHandle自定义使用ref时暴露给父组件的实例值。

使用类组件的遗留API (>= react@16.4)

const { Component } = React; class Parent extends Component { constructor(props) { super(props); this.child = React.createRef(); } onClick = () => { this.child.current.getAlert(); }; render() { return ( <div> <Child ref={this.child} /> <button onClick={this.onClick}>Click</button> </div> ); } } class Child extends Component { getAlert() { alert('getAlert from Child'); } render() { return <h1>Hello</h1>; } } ReactDOM.render(<Parent />, document.getElementById('root')); <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script> <div id="root"></div>

回调参考API

回调风格的引用是实现这一点的另一种方法,尽管在现代React中不太常见:

const { Component } = React; const { render } = ReactDOM; class Parent extends Component { render() { return ( <div> <Child ref={instance => { this.child = instance; }} /> <button onClick={() => { this.child.getAlert(); }}>Click</button> </div> ); } } class Child extends Component { getAlert() { alert('clicked'); } render() { return ( <h1>Hello</h1> ); } } render( <Parent />, document.getElementById('app') ); <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="app"></div>

https://facebook.github.io/react/tips/expose-component-functions.html 更多答案请参考这里调用React子组件上的方法

通过查看“reason”组件的引用,您正在破坏封装,如果不仔细检查使用该组件的所有位置,就不可能重构该组件。正因为如此,我们强烈建议将引用视为组件的私有,就像状态一样。

一般来说,数据应该通过道具沿着树向下传递。有一些例外情况(比如调用.focus()或触发一个不会真正“改变”状态的一次性动画),但任何时候你要公开一个名为“set”的方法,道具通常是更好的选择。试着让内部输入组件担心它的大小和外观,这样它的祖先就不会担心。

这个模式类似于@brickingup answer。但是在这个版本中,你可以设置任意多的子动作。

import { useEffect } from "react";

export const Parent = () => {
  const childEvents = { click: () => {} };

  return (
    <div onClick={() => childEvents.click()}>
      <Child events={childEvents}></Child>
    </div>
  );
};

export const Child = (props) => {
  const click = () => {
    alert("click from child");
  };

  useEffect(() => {
    if (props.events) {
      props.events.click = click;
    }
  }, []);

  return <span>Child Component</span>;
};

对于功能组件,最简单的方法是

父组件

parent.tsx

import React, { useEffect, useState, useRef } from "react";
import child from "../../child"

const parent: React.FunctionComponent = () => {
  const childRef: any = useRef();
}

const onDropDownChange: any = (event): void => {
    const target = event.target;
    childRef.current.onFilterChange(target.value);
};

return <child ref={childRef} />

export default parent;

子组件

child.tsx

import React, {   useState,   useEffect,   forwardRef,   useRef,   useImperativeHandle, } from "react";

const Child = forwardRef((props, ref) => {
 useImperativeHandle(ref, () => ({
    onFilterChange(id) {
      console.log("Value from parent", id)
    },
  }));
})

Child.displayName = "Child";

export default Child;

这里有个虫子?注意: 我同意rossipedia的解决方案使用forwardRef, useRef, useImperativeHandle

网上有一些错误的信息说refs只能从React类组件创建,但如果你使用上面提到的钩子,你确实可以使用函数组件。注意,只有在我将文件更改为在导出组件时不使用withRouter()后,钩子才对我有效。例如,从

export default withRouter(TableConfig);

取而代之的是

export default TableConfig;

In hindsight the withRouter() is not needed for such a component anyway, but usually it doesn't hurt anything having it in. My use case is that I created a component to create a Table to handle the viewing and editing of config values, and I wanted to be able to tell this Child component to reset it's state values whenever the Parent form's Reset button was hit. UseRef() wouldn't properly get the ref or ref.current (kept on getting null) until I removed withRouter() from the file containing my child component TableConfig