У меня есть два компонента.
Я пытался вызвать дочерний метод из 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>
);
}
}
Есть ли способ вызвать дочерний метод от родителя?
Примечание: дочерний и родительский компоненты находятся в двух разных файлах
Вы можете использовать ссылки
Ранее ссылки поддерживались только для компонентов на основе классов. С появлением React Hooks это уже не так
react@next
)Крючки нестабильны и только перед выпуском. API может (и, скорее всего, изменится).
import React, { forwardRef, useRef, useImperativeHandle } from '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>
);
};
Документация для useImperativeMethods()
находится здесь:
useImperativeMethods
настраивает значение экземпляра, которое предоставляется родительским компонентам при использованииref
.
react@stable
)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'));
<= [email protected]
)Для исторических целей здесь используется стиль на основе обратного вызова, который вы бы использовали с версиями React до 16.3:
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 при монтировании дочернего элемента. Таким образом, когда вы нажимаете кнопку в родительском элементе, она вызывает метод clickChild, который вызывает дочерний метод getAlert.
Это также работает, если ваш ребенок обернут в connect(), поэтому вам не нужен хак getWrappedInstance().
Обратите внимание, что вы не можете использовать onClick = {this.clickChild} в parent, потому что когда родительский элемент отображается, дочерний элемент не монтируется, поэтому this.clickChild еще не назначен. Использование onClick = {() => this.clickChild()} хорошо, потому что при нажатии кнопки this.clickChild уже должен быть назначен.
_this2.clickChild is not a function
почему?
https://facebook.github.io/react/tips/expose-component-functions.html подробнее см. здесь Вызовите методы для компонентов React children
Изучая ссылки на "причину", вы нарушаете инкапсуляцию и не можете реорганизовать этот компонент без тщательного изучения всех используемых им мест. Из-за этого мы настоятельно рекомендуем обрабатывать ссылки как частные для компонента, как состояние.
В общем, данные должны передаваться по дереву через реквизиты. Есть несколько исключений из этого (например, вызов.фокуса() или запуск одноразовой анимации, которая на самом деле не "изменяет" состояние), но в любое время, когда вы подвергаете метод "set", реквизиты обычно лучший выбор. Постарайтесь сделать так, чтобы внутренний компонент ввода беспокоился о его размере и внешности, чтобы ни один из его предков не делал.
Если вы делаете это просто потому, что хотите, чтобы 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, но некоторые люди могут оказаться здесь (как и мы), потому что они хотели создать черту многократного использования и думали, что дочерний компонент - хороший способ сделать это.
Мы можем использовать ссылки другим способом 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-
Надеюсь поможет тебе!
Я думаю, что самый простой способ вызова методов - это установить запрос на дочерний компонент. Затем, как только ребенок обрабатывает запрос, он вызывает метод обратного вызова для сброса запроса.
Механизм сброса необходим, чтобы иметь возможность отправлять один и тот же запрос несколько раз друг за другом.
В методе рендеринга родителя:
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();
}
Вы можете сделать Inveritance Inversion (посмотрите его здесь: https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e). Таким образом, у вас есть доступ к экземпляру компонента, который вы бы обернули (таким образом, вы сможете получить доступ к его функциям)