Rufen Sie eine React-Komponentenmethode von außen auf

91

Ich möchte eine Methode aufrufen, die von einer React-Komponente aus der Instanz eines React-Elements verfügbar gemacht wird.

Zum Beispiel in dieser jsfiddle . Ich möchte die alertMessageMethode aus der HelloElementReferenz aufrufen .

Gibt es eine Möglichkeit, dies zu erreichen, ohne zusätzliche Wrapper schreiben zu müssen?

Bearbeiten (kopierter Code von JSFiddle)

<div id="container"></div>
<button onclick="onButtonClick()">Click me!</button>
var onButtonClick = function () {

    //call alertMessage method from the reference of a React Element! Something like HelloElement.alertMessage()
    console.log("clicked!");
}

var Hello = React.createClass({displayName: 'Hello',

    alertMessage: function() {
        alert(this.props.name);                             
    },

    render: function() {
        return React.createElement("div", null, "Hello ", this.props.name);
    }
});

var HelloElement = React.createElement(Hello, {name: "World"});

React.render(
    HelloElement,
    document.getElementById('container')
);
Reicher Krieger
quelle
3
Nicht ideal, aber JSFiddle ist häufig genug, um eine Abwertung nicht zu rechtfertigen.
Jeff Fairley
Ich frage mich, was Ihr Anwendungsfall sein könnte, der so etwas rechtfertigen würde. Dies ist kein guter Weg, um Ihre Anwendung imo zu entwerfen. Wenn Sie etwas wiederverwenden müssen, erstellen Sie bitte einen separaten allgemeinen Helfer in einer dritten Datei und verwenden Sie ihn sowohl für Ihre Schaltfläche als auch für Ihre Reaktionskomponente.
Tee am

Antworten:

55

Es gibt zwei Möglichkeiten, auf eine innere Funktion zuzugreifen. Eine Instanzebene, wie Sie möchten, eine andere statische Ebene.

Beispiel

Sie müssen die Funktion bei der Rückkehr von aufrufen React.render. Siehe unten.

Statisch

Schauen Sie sich ReactJS Statics an . Beachten Sie jedoch, dass eine statische Funktion nicht auf Daten auf Instanzebene zugreifen thiskann undefined.

var onButtonClick = function () {
    //call alertMessage method from the reference of a React Element! 
    HelloRendered.alertMessage();
    //call static alertMessage method from the reference of a React Class! 
    Hello.alertMessage();
    console.log("clicked!");
}

var Hello = React.createClass({
    displayName: 'Hello',
    statics: {
        alertMessage: function () {
            alert('static message');
        }
    },
    alertMessage: function () {
        alert(this.props.name);
    },

    render: function () {
        return React.createElement("div", null, "Hello ", this.props.name);
    }
});

var HelloElement = React.createElement(Hello, {
    name: "World"
});

var HelloRendered = React.render(HelloElement, document.getElementById('container'));

Dann mach es HelloRendered.alertMessage().

Jeff Fairley
quelle
13
Beachten Sie, dass die Verwendung des Rückgabewerts von render als veraltet gilt und voraussichtlich in zukünftigen Versionen entfernt wird, um Leistungsverbesserungen zu ermöglichen. Die unterstützte Methode zum Abrufen eines Verweises auf Ihr Komponenteninstanzobjekt besteht darin, eine Eigenschaft hinzuzufügen, refdie eine Funktion ist, die mit der Instanz als Parameter aufgerufen wird. Auf diese Weise können Sie auch auf Objekte zugreifen, die sich nicht auf der obersten Ebene befinden. Wenn Sie beispielsweise rendern <MuiThemeProvider><Hello ref={setHelloRef} /></MuiThemeProvider>, wird die richtige Referenz an Ihre setHelloRefFunktion übergeben und nicht an eine MuiThemeProvider.
Periata Breatta
43

Sie können gerne tun

import React from 'react';

class Header extends React.Component{

    constructor(){
        super();
        window.helloComponent = this;
    }

    alertMessage(){
       console.log("Called from outside");
    }

    render(){

      return (
      <AppBar style={{background:'#000'}}>
        Hello
      </AppBar>
      )
    }
}

export default Header;

Jetzt können Sie von außerhalb dieser Komponente wie folgt aufrufen

window.helloComponent.alertMessage();
Kushal Jain
quelle
1
In der Tat einfach und funktional! Wie es sein soll. Ich bin sehr beeindruckt, wie einfach es ist; Ich habe wirklich nicht darüber nachgedacht. Wahrscheinlich funktioniert dieser Ansatz nicht so gut, wenn Sie immer mehr Komponenten benötigen. Danke dir!
Leonardo Maffei
6
Das Hinzufügen einer globalen Variablen ist keine gute Lösung. Mehr darüber, warum globale Variablen schlecht sind, hier: wiki.c2.com/?GlobalVariablesAreBad
Salvatore Zappalà
3
Danke für die Abstimmung !! Ja, globale Variablen sind nicht gut, aber das ist ein Weg, um Ihr Problem zu lösen.
Kushal Jain
Dies ist genau die pragmatische und einfache Lösung, die ich brauchte, danke!
Florent Destremau
2
Es hat funktioniert, aber es funktioniert nicht, wenn Sie mehrere Komponenten auf derselben Seite haben.
Gaurav
24

Ich habe so etwas gemacht:

class Cow extends React.Component {

    constructor (props) {
        super(props);
        this.state = {text: 'hello'};
    }

    componentDidMount () {
        if (this.props.onMounted) {
            this.props.onMounted({
                say: text => this.say(text)
            });
        }
    }

    render () {
        return (
            <pre>
                 ___________________
                < {this.state.text} >
                 -------------------
                        \   ^__^
                         \  (oo)\_______
                            (__)\       )\/\
                                ||----w |
                                ||     ||
            </pre>
        );
    }

    say (text) {
        this.setState({text: text});
    }

}

Und dann woanders:

class Pasture extends React.Component {

    render () {
        return (
            <div>
                <Cow onMounted={callbacks => this.cowMounted(callbacks)} />
                <button onClick={() => this.changeCow()} />
            </div>
        );
    }

    cowMounted (callbacks) {
        this.cowCallbacks = callbacks;
    }

    changeCow () {
        this.cowCallbacks.say('moo');
    }

}

Ich habe diesen genauen Code nicht getestet, aber dies entspricht dem, was ich in einem meiner Projekte getan habe, und es funktioniert gut :). Natürlich ist dies ein schlechtes Beispiel, Sie sollten nur Requisiten dafür verwenden, aber in meinem Fall hat die Unterkomponente einen API-Aufruf ausgeführt, den ich in dieser Komponente behalten wollte. In einem solchen Fall ist dies eine gute Lösung.

Gitaarik
quelle
5
Ich denke du meintestthis.cowCallbacks.say('moo')
Steven
Übrigens ist es möglich, statt an thisden Rückruf (der eine Instanz von Cow sein wird) zu übergeben callbacks.
WebBrother
@ WebBrother Ja, aber das wäre noch hackiger
Gitaarik
6

Da die renderMethode den zurückgegebenen Wert möglicherweise nicht mehr unterstützt, wird jetzt empfohlen, dem Stammelement eine Rückrufreferenz zuzuweisen. So was:

ReactDOM.render( <Hello name="World" ref={(element) => {window.helloComponent = element}}/>, document.getElementById('container'));

auf die wir dann mit window.helloComponent zugreifen können, und auf jede ihrer Methoden kann mit window.helloComponent.METHOD zugegriffen werden.

Hier ist ein vollständiges Beispiel:

var onButtonClick = function() {
  window.helloComponent.alertMessage();
}

class Hello extends React.Component {
  alertMessage() {
    alert(this.props.name);
  }

  render() {
    return React.createElement("div", null, "Hello ", this.props.name);
  }
};

ReactDOM.render( <Hello name="World" ref={(element) => {window.helloComponent = element}}/>, document.getElementById('container'));
<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="container"></div>
<button onclick="onButtonClick()">Click me!</button>

Brett DeWoody
quelle
Besser, die Referenz in den lokalen Zustand zu versetzen, als auf das Fensterobjekt ... ref={component => {this.setState({ helloComponent: component; })}} Dann im Klick-Handler ... this.state.helloComponent.alertMessage();
Bill Dagg
Weiter zu meinem vorherigen Kommentar ... oder, noch besser, setzen Sie einfach die alertMessage-Methode der Komponente in den Status.
Bill Dagg
4
class AppProvider extends Component {
  constructor() {
    super();

    window.alertMessage = this.alertMessage.bind(this);
  }

  alertMessage() {
    console.log('Hello World');
 }
}

Sie können diese Methode aus dem Fenster mit aufrufen window.alertMessage().

Mygel Bergstresser
quelle
Dies würde funktionieren, aber das Hinzufügen einer globalen Variablen ist aus vielen Gründen keine gute Lösung. Weitere Informationen darüber, warum globale Variablen schlecht sind, finden Sie hier: wiki.c2.com/?GlobalVariablesAreBad
Salvatore Zappalà
3

Wenn Sie in ES6 sind, verwenden Sie einfach das Schlüsselwort "static" für Ihre Methode aus Ihrem Beispiel: static alertMessage: function() { ...
},

Hoffnung kann jedem da draußen helfen :)

Darmis
quelle
Sie können in einer statischen Funktion keine Requisiten oder Zustände erreichen.
Serdar Değirmenci
Ok ja, aber die Frage war im Begriff, auf die Funktion alertMessage () zuzugreifen, damit Sie HelloElement.alertMessage () verwenden können.
Darmis
Im Allgemeinen hat das Aufrufen einer Funktion ohne Verwendung von Requisiten und Status keine Auswirkung. Aber da Sie Recht haben, die Funktion zu erreichen, entferne ich meine Stimme
Serdar Değirmenci
2

Sie können onClickdem div einfach einen Handler mit der Funktion hinzufügen ( onClickist Reacts eigene Implementierung von onClick) und Sie können in { }geschweiften Klammern auf die Eigenschaft zugreifen , und Ihre Warnmeldung wird angezeigt.

Wenn Sie statische Methoden definieren möchten, die für die Komponentenklasse aufgerufen werden können, sollten Sie statische Methoden verwenden. Obwohl:

"In diesem Block definierte Methoden sind statisch. Dies bedeutet, dass Sie sie ausführen können, bevor Komponenteninstanzen erstellt werden. Die Methoden haben keinen Zugriff auf die Requisiten oder den Status Ihrer Komponenten. Wenn Sie den Wert von Requisiten in einer Statik überprüfen möchten Methode, lassen Sie den Aufrufer in den Requisiten als Argument an die statische Methode übergeben. " ( Quelle )

Ein Beispielcode:

    const Hello = React.createClass({

        /*
            The statics object allows you to define static methods that can be called on the component class. For example:
        */
        statics: {
            customMethod: function(foo) {
              return foo === 'bar';
            }
        },


        alertMessage: function() {
            alert(this.props.name);                             
        },

        render: function () {
            return (
                <div onClick={this.alertMessage}>
                Hello {this.props.name}
                </div>
            );
        }
    });

    React.render(<Hello name={'aworld'} />, document.body);

Hoffe das hilft dir ein bisschen, denn ich weiß nicht ob ich deine Frage richtig verstanden habe, also korrigiere mich wenn ich sie falsch interpretiert habe :)

Danillo Felixdaal
quelle
2

Es scheint, dass die Statik veraltet ist und die anderen Methoden zum Anzeigen einiger Funktionen renderverworren sind. In der Zwischenzeit hat diese Stack Overflow-Antwort zum Debuggen von React , obwohl sie hackig zu sein scheint, den Job für mich erledigt.

philipkd
quelle
2

Methode 1 using ChildRef :

public childRef: any = React.createRef<Hello>();

public onButtonClick= () => {
    console.log(this.childRef.current); // this will have your child reference
}

<Hello ref = { this.childRef }/>
<button onclick="onButtonClick()">Click me!</button>

Methode 2: using window register

public onButtonClick= () => {
    console.log(window.yourRef); // this will have your child reference
}

<Hello ref = { (ref) => {window.yourRef = ref} }/>`
<button onclick="onButtonClick()">Click me!</button>
Mohideen bin Mohammed
quelle
Methode 1 ist eine sehr einfache und saubere Möglichkeit, auf untergeordnete Komponentenmethoden zuzugreifen. Vielen Dank!
Gabdara
2

Mit React hook - useRef



const MyComponent = ({myRef}) => {
  const handleClick = () => alert('hello world')
  myRef.current.handleClick = handleClick
  return (<button onClick={handleClick}>Original Button</button>)
}

MyComponent.defaultProps = {
  myRef: {current: {}}
}

const MyParentComponent = () => {
  const myRef = React.useRef({})
  return (
    <>
      <MyComponent 
        myRef={myRef}
      />
      <button onClick={myRef.curent.handleClick}>
        Additional Button
      </button>
    </>
  )
}

Viel Glück...

Akash
quelle
1

Ich verwende diese Hilfsmethode, um Komponenten zu rendern und eine Komponenteninstanz zurückzugeben. In dieser Instanz können Methoden aufgerufen werden.

static async renderComponentAt(componentClass, props, parentElementId){
         let componentId = props.id;
        if(!componentId){
            throw Error('Component has no id property. Please include id:"...xyz..." to component properties.');
        }

        let parentElement = document.getElementById(parentElementId);

        return await new Promise((resolve, reject) => {
            props.ref = (component)=>{
                resolve(component);
            };
            let element = React.createElement(componentClass, props, null);
            ReactDOM.render(element, parentElement);
        });
    }
Stefan
quelle