Вызов дочернего метода от родителя

У меня есть два компонента.

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

есть ли способ вызвать метод ребенка от родителя ?

Примечание: дочерние и родительские компоненты находятся в двух разных файлах

5 ответов


можно использовать refs:

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


я обновил этот пример, чтобы отразить изменения в React 16.3, который использует новый метод обработки ссылок. Я оставил оригинальную версию обратного вызова ниже, так как она все еще работает. (Я верну embed здесь, как только я получу React 16.3 и запущу на фрагментах стека)


редактировать

строка рефов вероятно, в будущем они будут устаревшими, поэтому вот как вы это сделаете с обратный вызов refs:

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>

вы можете использовать другой шаблон здесь:

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 при монтировании дочернего элемента. Таким образом, когда вы нажмете кнопку в parent, он вызовет clickChild, который вызывает getAlert ребенка.

Это также работает, если ваш ребенок завернут в connect (), поэтому вам не нужен взлом getWrappedInstance ().

Примечание. Вы не можете использовать onClick={this.clickChild} в parent, потому что при отображении parent дочерний элемент не монтируется вот так.clickChild еще не назначен. Используя onClick= {() = > this.clickChild ()} отлично, потому что при нажатии кнопки это.clickChild уже должен быть назначен.


https://facebook.github.io/react/tips/expose-component-functions.html для получения дополнительных ответов ref здесь методы вызова на реагируют дочерние компоненты

просматривая ссылки компонента "причина", вы нарушаете инкапсуляцию и делаете невозможным рефакторинг этого компонента без тщательного изучения всех мест, где он используется. Из-за этого мы настоятельно рекомендуем рассматривать ссылки как частные для компонента, например государство.

В общем случае данные должны передаваться по дереву через реквизит. Есть несколько исключений из этого (например, вызов .фокус () или запуск одноразовой анимации, которая на самом деле не "меняет" состояние), но в любое время, когда вы подвергаете методу под названием "set", реквизит обычно является лучшим выбором. Постарайтесь сделать так, чтобы внутренний входной компонент беспокоился о своем размере и внешнем виде, чтобы никто из его предков этого не делал.


если вы делаете это просто потому, что хотите, чтобы ребенок предоставил повторно используемую черту своим родителям, тогда вы можете подумать об этом использование render-props.

эта техника фактически переворачивает структуру вверх дном. The 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 как упорка, и может вызвать ее когда нужно.

(для ясности, я назвал проп renderComponent в приведенном выше примере. Но в документах React, связанных выше, они просто называют это render.)

компонент признака может отображать материал, окружающий родителя, в его функции визуализации, но он ничего не отображает внутри родителя. На самом деле он может отображать вещи внутри родителя, если он передал другую опору (например,renderChild) к родителю, который родитель может использовать во время своего метода рендеринга.

это несколько отличается от того, что просил OP, но некоторые люди могут оказаться здесь (как и мы), потому что они хотели создать многоразовую черту и думали, что дочерний компонент-хороший способ сделать это.


вы можете сделать инверсию наследования (посмотрите здесь:https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e). Таким образом, у вас есть доступ к экземпляру компонента, который вы будете обертывать (таким образом, Вы сможете получить доступ к его функциям)