從父級調用子級方法

我有兩個組成部分。 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要求的有所不一樣,但有些人可能會像咱們同樣最終來到這裏(由於咱們這樣作了),由於他們想建立可重用的特徵,並認爲子組件是實現此目標的好方法。

相關文章
相關標籤/搜索