Вызов метода child из родительского

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

  1. Родительский компонент
  2. Дочерний компонент

Я пытался вызвать дочерний метод из Parent, я пытался таким образом, но не смог получить результат

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

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

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

Ответ 1

Прежде всего, позвольте мне сказать, что это вообще не тот способ, которым можно заниматься в React Land. Обычно вы хотите передать функциональность дочерним элементам в подпорках и передать уведомления от дочерних элементов в событиях (или еще лучше: dispatch).

Но если вам необходимо предоставить обязательный метод для дочернего компонента, вы можете использовать refs. Помните, что это аварийный люк, который обычно указывает на лучший дизайн.

Ранее ссылки поддерживались только для компонентов на основе классов. С появлением React Hooks это уже не так

Использование хуков и функциональных компонентов (>= [email protected])

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/[email protected]/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js" crossorigin></script>

<div id="root"></div>

Ответ 2

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

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 она вызывает clickChild который вызывает дочерний getAlert.

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

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

Ответ 3

https://facebook.github.io/react/tips/expose-component-functions.html подробнее см. здесь Вызовите методы для компонентов React children

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

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

Ответ 4

Мы можем использовать ссылки другим способом as-

Мы собираемся создать элемент Parent, он будет отображать компонент <Child/>. Как видите, для компонента, который будет отображаться, нужно добавить атрибут ref и указать для него имя.
Затем функция triggerChildAlert, расположенная в родительском классе, получит доступ к свойству refs этого контекста (когда triggerChildAlert функция triggerChildAlert получит доступ к дочерней ссылке, и у нее будут все функции дочернего элемента).

class Parent extends React.Component {
    triggerChildAlert(){
        this.refs.child.callChildMethod();
        // to get child parent returned  value-
        // this.value = this.refs.child.callChildMethod();
        // alert('Returned value- '+this.value);
    }

    render() {
        return (
            <div>
                {/* Note that you need to give a value to the ref parameter, in this case child*/}
                <Child ref="child" />
                <button onClick={this.triggerChildAlert}>Click</button>
            </div>
        );
    }
}  

Теперь дочерний компонент, как теоретически разработано ранее, будет выглядеть так:

class Child extends React.Component {
    callChildMethod() {
        alert('Hello World');
        // to return some value
        // return this.state.someValue;
    }

    render() {
        return (
            <h1>Hello</h1>
        );
    }
}

Вот источник code-
Надеюсь поможет тебе!

Ответ 5

Если вы делаете это просто потому, что хотите, чтобы Child предоставил своим родителям повторно используемую черту, то вы можете вместо этого сделать это с помощью 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 документах они просто вызывают это render.)

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

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

Ответ 6

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

Ответ 7

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

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

В родительском компоненте

В методе рендеринга родителя:

const { request } = this.state;
return (<Child request={request} onRequestHandled={()->resetRequest()}/>);

Родителю нужно 2 метода, чтобы общаться с ребенком в 2 направлениях.

sendRequest() {
  const request = { param: "value" };
  this.setState({ request });
}

resetRequest() {
  const request = null;
  this.setState({ request });
}

В дочернем компоненте

Ребенок обновляет свое внутреннее состояние, копируя запрос с реквизита.

constructor(props) {
  super(props);
  const { request } = props;
  this.state = { request };
}

static getDerivedStateFromProps(props, state) {
  const { request } = props;
  if (request !== state.request ) return { request };
  return null;
}

Затем, наконец, он обрабатывает запрос и отправляет сброс родителю:

componentDidMount() {
  const { request } = this.state;
  // todo handle request.

  const { onRequestHandled } = this.props;
  if (onRequestHandled != null) onRequestHandled();
}

Ответ 8

Вы можете легко достичь этого

Steps-

  1. Создайте логическую переменную в состоянии в родительском классе. Обновите это, когда вы хотите вызвать функцию.
  2. Создайте переменную prop и присвойте логическую переменную.
  3. Из дочернего компонента обращайтесь к этой переменной с помощью props и выполняйте нужный метод, используя условие if.

    class Child extends Component {
       Method=()=>{
       --Your method body--
       }
       render() {
         return (
        //check whether the variable has been updated or not
          if(this.props.updateMethod){
            this.Method();
          }
         )
       }
    }
    
    class Parent extends Component {
    
    constructor(){
      this.state={
       callMethod:false
      }
    
    }
    render() {
       return (
    
         //update state according to your requirement
         this.setState({
            callMethod:true
         }}
         <Child updateMethod={this.state.callMethod}></Child>
        );
       }
    }