从父级调用子级方法

我有两个组成部分。 html

  1. 父组件
  2. 子组件

我试图从父级调用孩子的方法,我尝试过这种方法,但没有获得结果 react

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

有没有一种方法能够从父级调用子级的方法? git

注意:子组件和父组件位于两个不一样的文件中 github


#1楼

首先,让我表示,这一般不是在React领域中解决问题的方法。 一般,您要作的是将功能传递给props中的子代,并传递事件中子代的通知(或者更好的是: dispatch )。 ajax

可是,若是必须在子组件上公开命令式方法,则可使用refs 。 请记住,这是一个逃生舱口,一般表示可使用更好的设计。 app

之前,仅基于类的组件才支持引用。 随着React Hooks的出现,状况再也不如此 dom

使用挂钩和功能组件( >= react@16.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()文档在这里ide

useImperativeHandle自定义使用ref时公开给父组件的实例值。 函数

使用类组件( >= 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@16.3

出于历史目的,这是您在16.3以前的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>


#2楼

https://facebook.github.io/react/tips/expose-component-functions.html有关更多答案的参考,请参见此处

经过查看“缘由”组件的引用,您正在破坏封装并使您没法仔细检查组件的全部使用位置就没法重构该组件。 所以,咱们强烈建议将ref视为组件的私有属性,就像state同样。

一般,数据应经过道具传递到树下。 有一些例外(例如,调用.focus()或触发一次不会真正“改变”状态的一次性动画),可是每当您公开称为“ set”的方法时,道具一般更好的选择。 尝试使其内部输入组件担忧其大小和外观,以便其祖先都不作。


#3楼

您能够在此处使用其余模式:

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方法。 这样,当您单击父级中的按钮时,它将调用clickChild ,后者将调用子级的getAlert

若是您的孩子用connect()包裹起来,那么这也能够工做,所以您不须要getWrappedInstance() hack。

请注意,您不能在父级中使用onClick={this.clickChild} ,由于在渲染父级时未安装子级,所以还没有分配this.clickChild 。 使用onClick={() => this.clickChild()}很好,由于单击按钮时this.clickChild应该已经被分配了。


#4楼

您能够进行继承反转(在此处查找: https : //medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e )。 这样,您就能够访问要包装的组件的实例(所以您将能够访问其功能)


#5楼

若是只是由于您但愿子项为其父项提供可重用的特征而这样作,则能够考虑使用render-props来实现。

该技术实际上使结构颠倒了。 Child如今包装了父级,所以我在下面将其重命名为AlertTrait 。 为了保持连续性,我保留了“ Parent这个名称,尽管如今它实际上并非父代。

// Use it like this:

  <AlertTrait renderComponent={Parent}/>


class AlertTrait extends Component {
  // You may need to bind this function, if it is stateful
  doAlert() {
    alert('clicked');
  }
  render() {
    return this.props.renderComponent(this.doAlert);
  }
}

class Parent extends Component {
  render() {
    return (
      <button onClick={this.props.doAlert}>Click</button>
    );
  }
}

在这种状况下,AlertTrait提供一个或多个特征,将其做为道具传递到其renderComponent道具中给定的任何组件。

父级收到doAlert做为道具,并能够在须要时调用它。

(为清楚起见,我在上面的示例中称为prop renderComponent 。可是在上面连接的React docs中,他们只是将其称为render 。)

Trait组件能够在其render函数中渲染围绕Parent的内容,但不会渲染Parent内部的任何内容。 实际上,若是它向父级传递了另外一个道具(例如renderChild ),则它能够在父级内部渲染事物,而后父级能够在其render方法中使用它。

这与OP要求的有所不一样,但有些人可能会像咱们同样最终来到这里(由于咱们这样作了),由于他们想建立可重用的特征,并认为子组件是实现此目标的好方法。

相关文章
相关标签/搜索