开发者问题收集

从父类调用子类方法

2016-06-21
851107

我有两个组件:

  1. 父组件
  2. 子组件

我试图从父组件调用子组件的方法,我尝试了这种方式但没有得到结果:

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

有没有办法从父组件调用子组件的方法?

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

3个回答

首先,我要说的是,这通常 不是 在 React 领域中处理事情的方式。通常您想要做的是将功能传递给 props 中的子组件,并在事件中传递来自子组件的通知(或者更好的是: dispatch )。

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

Previously, refs were only supported for Class-based components. With the advent of React Hooks , that's no longer the case

带有 Hooks 的现代 React ( 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 customizes the instance value that is exposed to parent components when using ref .

使用类组件的旧版 API ( >= [email protected] )

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>

回调 Ref API

回调样式的 refs 是实现此目的的另一种方法,尽管在现代 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>
rossipedia
2016-06-21

您可以在此处使用另一种模式:

class Parent extends Component {
 render() {
  return (
    <div>
      <Child setClick={click => this.clickChild = click}/>
      <button onClick={() => this.clickChild()}>Click</button>
    </div>
  );
 }
}

class Child extends Component {
 constructor(props) {
    super(props);
    this.getAlert = this.getAlert.bind(this);
 }
 componentDidMount() {
    this.props.setClick(this.getAlert);
 }
 getAlert() {
    alert('clicked');
 }
 render() {
  return (
    <h1 ref="hello">Hello</h1>
  );
 }
}

它的作用是在子级挂载时设置父级的 clickChild 方法。这样,当您单击父级中的按钮时,它将调用 clickChild ,而后者又调用子级的 getAlert

如果您的子级使用 connect() 包装,此方法也有效,因此您不需要 getWrappedInstance() 黑客攻击。

请注意,您不能在父级中使用 onClick={this.clickChild ,因为当呈现父级时,子级尚未挂载,因此 this.clickChild 尚未分配。使用 onClick={() => this.clickChild() 是可以的,因为当您单击按钮时, this.clickChild 应该已经分配。

brickingup
2017-08-09

使用 useEffect 的替代方法:

父级:

const [refresh, doRefresh] = useState(0);
<Button onClick={() => doRefresh(prev => prev + 1)} />
<Children refresh={refresh} />

子级:

useEffect(() => {
    performRefresh(); //children function of interest
  }, [props.refresh]);
tonymayoral
2020-03-18