2017-02-14 4 views
2

Ich versuche, die Ursache für ein seltsames Verhalten in der Bindung von this in einer React-Komponente zu finden.Was passiert mit der Bindung von React?

Ich bin es gewohnt, Komponenten zu entwickeln und ihre Methoden im Klassenkörper zu platzieren und sie an die Komponente this innerhalb der constructor zu binden. Vor kurzem entschied ich jedoch, dass ich Dinge aufräumen und Bedenken lösen wollte, indem ich einige dieser großen Methoden zu separaten Dateien extrahieren und sie dann in die Komponente importiere.

Zu meiner Bestürzung funktioniert die Bindung this in diesem Fall nicht so einfach. Noch seltsamer, während die Verwendung einer ES6-Pfeil-Funktion nicht richtig zu binden scheint, funktioniert die Verwendung einer grundlegenden ES5-Funktion gut. Ich versuche, die Ursache für dieses Verhalten, um herauszufinden:

Beispiel 1

import React, { Component } from 'react'; 

class App extends Component { 
    constructor(props) { 
    super(props); 
    this.changeName = this.changeName.bind(this); 
    this.state = { 
     name: 'John' 
    }; 
    } 

    changeName() { 
    this.setState({ 
     ...this.state, 
     name: 'Jane' 
    }); 
    } 
... 

Beispiel 2 [wie erwartet funktioniert] [NICHT ARBEITEN - Typeerror: kann Eigenschaft ‚setState‘ undefinierten lesen]

App.js

import React, { Component } from 'react'; 
import changeName from './change-name'; 

class App extends Component { 
    constructor(props) { 
    super(props); 
    this.changeName = changeName.bind(this); 
    this.state = { 
     name: 'John' 
    }; 
    } 
... 

change-name.js

Beispiel [funktioniert wie erwartet - die gleichen App.js wie in Beispiel 2]

change-name.js

function changeName() { 
    this.setState({ 
    ...this.state, 
    name: 'Jane' 
    }); 
}; 

module.exports = changeName; 

Antwort

3

Dieses Verhalten ist ein richtiges Pfeil Funktion Verhalten.

Siehe docs:

An arrow function expression has a shorter syntax than a function expression and does not bind its own this, arguments, super, or new.target. Arrow functions are always anonymous. These function expressions are best suited for non-method functions, and they cannot be used as constructors.

Dieser Teil nicht bindet seine eigene diese ist diejenige, die Sie über fragen. Arrow-Funktion nimmt this aus dem Kontext, umgibt diese Funktionsdeklaration.

+1

Ahh, ich sehe jetzt. Ich hatte den Eindruck, eine 'const'-Pfeilfunktion sei synonym mit einer ES5-Funktion. Vielen Dank! – aware

+0

Also in der Konstruktorfunktion der React-Komponente warum gibt 'this.changeN = changeName' der importierten Funktion nicht ihr' this'? Angenommen, 'changeName' ist die importierte Funktion (definiert als Pfeilfunktion). – aware

+0

, da die Funktionsinstanz changeName diese explizit aus der Umgebung entnimmt, in der sie deklariert ist. Stellen Sie sich das als normale Funktion vor, aber an das äußere 'This' gebunden:' changeName.bind (this) 'wobei' this' das 'this' der Stelle der Pfeilfunktionsdeklaration ist – smnbbrv

3

Dies ist der neue es6-Funktionsstil. Sie müssen Ihr Methid nicht binden, wenn Sie es6 Pfeilfunktion verwenden.

Entfernen Binding-Anweisung von Konstruktor und es sollte funktionieren.

+1

Wow. Ich kann nicht glauben, dass es so einfach war.Obwohl ich noch 'this' an die Methode binden muss, wenn ich sie innerhalb der Komponente verwende, so wie' '(was mich immer noch verwirrt, warum binding im Konstruktor funktioniert nicht) ... aber trotzdem ist das eine gute Lösung für mich! Danke – aware

+0

Funktionskontext wird immer beim Aufruf der Funktion definiert. Wenn Sie nicht binden auf onClick attr. dann wird es Fenster als seinen Kontext Kontext nehmen, der Fehler wirft. –

+0

Nicht für Pfeilfunktionen. Arrow-Funktionen lösen "dies" lexikalisch auf. –

0

Ich bevorzuge diese Syntax. Es funktioniert völlig ohne Bindung:

class Something extends React.Component { 
    changeName =() => { 
     // Works 
    } 

    render() { 
     // Add input, div or something with onChange or onClick 
    } 
} 

export default Something 
+0

Danke für den Vorschlag, obwohl ich bereits darüber informiert bin, dass verfügbar. Ich suchte nach einer Möglichkeit, die Methode 'changeName' in einer separaten Datei zu behalten und sie in die Komponente (n) zu importieren, in der sie verwendet wird. – aware