Korrekte Verwendung von Pfeilfunktionen in React

Lesezeit: 10 Minuten

Korrekte Verwendung von Pfeilfunktionen in React
kojow7

Ich verwende ReactJS mit Babel und Webpack und verwende ES6 sowie die vorgeschlagene Klassenfelder für Pfeilfunktionen. Ich verstehe, dass Pfeilfunktionen die Dinge effizienter machen die Funktionen werden nicht bei jedem Rendern neu erstellt ähnlich wie die Bindung im Konstruktor funktioniert. Allerdings bin ich mir nicht 100% sicher, ob ich sie richtig verwende. Das Folgende ist ein vereinfachter Abschnitt meines Codes in drei verschiedenen Dateien.

Mein Code:

Main.js

prevItem = () => {
    console.log("Div is clicked")
}

render(){
    return (
         <SecondClass prevItem={this.prevItem} />
    )
}

SecondClass.js

<ThirdClass type="prev" onClick={()=>this.props.prevItem()} />

ThirdClass.js

<div onClick={()=>{this.props.onClick()}}>Previous</div>

Frage:

Verwendet mein obiger Code die Pfeilfunktionen korrekt? Mir ist aufgefallen, dass ich für SecondClass.js auch hätte verwenden können:

<ThirdClass type="prev" onClick={this.props.prevItem} />

Gibt es einen Unterschied zwischen der einen oder anderen Methode, da ich in meiner ursprünglichen Funktionsdefinition eine ES6-Pfeilfunktion verwendet habe? Oder sollte ich die Pfeilsyntax bis zu meinem letzten div verwenden?

  • developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… hier ist mehr detail..

    – Zi Gang

    9. Februar 18 um 6:03 Uhr

  • onClick={this.props.prevItem} hier, da es keinen Hinweis darauf gibt this in prevItem, du kannst es benutzen. Wenn Sie jedoch Code auf Bereichsebene hinzufügen, wird er beschädigt. Da Sie eine Funktion von einem Objekt zuweisen und aufrufen, verliert sie ihren Kontext.

    – Rajesh

    9. Februar 18 um 6:07 Uhr

  • Zu Ihrer Information, Klassenfelder sind nicht Teil von ES6

    – Felix Klinge

    9. Februar 18 um 7:10 Uhr

  • mögliches Duplikat von Wie verwende ich Pfeilfunktionen (öffentliche Klassenfelder) als Klassenmethoden?

    – Bergi

    29. Oktober 20 um 20:42 Uhr

Korrekte Verwendung von Pfeilfunktionen in React
Sagiv bg

Ich verstehe, dass Pfeilfunktionen die Dinge effizienter machen, indem sie die Funktionen nicht jedes Mal neu erstellen, wenn auf sie verwiesen wird

Das ist nicht wahr.

Pfeilfunktionen behandeln die this Kontext auf lexikalische Weise, wo “normale” Funktionen dies tun dynamisch. Ich habe darüber geschrieben das dieses Schlüsselwort in der Tiefe wenn Sie mehr Informationen darüber benötigen.

In beiden Beispielen der Inline-Pfeilfunktion erstellen Sie jeweils eine neue Funktionsinstanz render.
Dadurch wird bei jedem Rendern eine neue Instanz erstellt und übergeben

onClick={() => {}}

Im 3. Beispiel haben Sie nur eine Instanz.
Dadurch wird nur eine Referenz auf eine bereits vorhandene Instanz übergeben

onClick={this.myHandler}


Zu den Vorteilen von Pfeilfunktionen als Klassenfelder (es gibt eine kleiner Nachteilich werde es am Ende der Antwort posten), wenn Sie einen normalen Funktionshandler haben, der auf die aktuelle Instanz von zugreifen muss class über this:

myHandler(){
  //  this.setState(...)
}

Sie müssen dies explizit machen bind es zum class.
Der gebräuchlichste Ansatz wird darin bestehen, dies in der zu tun constructor weil es nur einmal läuft:

constructor(props){
  super(props);
  this.myHandler = this.myHandler.bind(this);
}

Wenn Sie jedoch eine Pfeilfunktion als Handler verwenden, müssen Sie dies nicht tun bind es zum class denn wie oben erwähnt, verwendet die Pfeilfunktion einen lexikalischen Kontext für this:

myHandler = () => {
  //  this.setState(...)
}

Bei beiden Ansätzen verwenden Sie den Handler wie folgt:

<div onClick={this.myHandler}></div> 

Der Hauptgrund für diesen Ansatz:

<div onClick={() => this.myHandler(someParameter)}></div>

Ist, wenn Sie neben dem nativen Parameter an den Handler übergeben möchten event die übergeben werden, was bedeutet, dass Sie einen Parameter nach oben übergeben möchten.

Wie bereits erwähnt, wird dadurch bei jedem Rendern eine neue Funktionsinstanz erstellt.
(Dafür gibt es einen besseren Ansatz, lesen Sie weiter).

Laufendes Beispiel für einen solchen Anwendungsfall:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      items: [{ name: 'item 1', active: false }, { name: 'item 2', active: true }],
    }
  }
  toggleITem = (itemName) => {
    this.setState(prev => {
      const nextState = prev.items.map(item => {
        if (item.name !== itemName) return item;
        return {
          ...item,
          active: !item.active
        }
      });
      return { items: nextState };
    });
  }
  render() {
    const { items } = this.state;
    return (
      <div>
        {
          items.map(item => {
            const style = { color: item.active ? 'green' : 'red' };
            return (
              <div
                onClick={() => this.toggleITem(item.name)}
                style={style}
              >
                {item.name}
              </div>
          
          )})
        }
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<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="root"></div>

Ein besserer Ansatz wäre, eine Komponentenzusammensetzung zu erstellen.
Sie können eine untergeordnete Komponente erstellen, die das relevante Markup umschließt, über einen eigenen Handler verfügt und sowohl die data und handler als Requisiten von den Eltern.

Die untergeordnete Komponente ruft dann den Handler auf, den sie von der übergeordneten Komponente erhalten hat, und übergibt die data als Parameter.

Laufendes Beispiel mit untergeordneter Komponente:

class Item extends React.Component {
  onClick = () => {
    const { onClick, name } = this.props;
    onClick(name);
  }
  render() {
    const { name, active } = this.props;
    const style = { color: active ? 'green' : 'red' };
    return (<div style={style} onClick={this.onClick}>{name}</div>)
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      items: [{ name: 'item 1', active: false }, { name: 'item 2', active: true }],
    }
  }
  toggleITem = (itemName) => {
    this.setState(prev => {
      const nextState = prev.items.map(item => {
        if (item.name !== itemName) return item;
        return {
          ...item,
          active: !item.active
        }
      });
      return { items: nextState };
    });
  }
  render() {
    const { items } = this.state;
    return (
      <div>
        {
          items.map(item => {
            return <Item {...item} onClick={this.toggleITem} />
          })
        }
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<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="root"></div>

Klassenfelder die Nachteil:
Wie ich bereits erwähnt habe, gibt es einen kleinen Nachteil für Klassenfelder.
Der Unterschied zwischen einer Klassenmethode und einem Klassenfeld besteht darin, dass das Klassenfeld an die angehängt ist instance des class (Konstruktorfunktion).
wobei die Klassenmethoden und -objekte an den Prototyp angehängt werden.

Wenn Sie also eine lächerlich große Anzahl von Instanzen dieser Klasse haben, werden Sie kann einen Performance-Hit bekommen.

Angesichts dieses Codeblocks:

class MyClass {
  myMethod(){}  
  myOtherMethod = () => {}
}

babel wird es folgendermaßen transpilieren:

var _createClass = function() {
  function defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }
  return function(Constructor, protoProps, staticProps) {
    if (protoProps) defineProperties(Constructor.prototype, protoProps);
    if (staticProps) defineProperties(Constructor, staticProps);
    return Constructor;
  };
}();

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var MyClass = function() {
  function MyClass() {
    _classCallCheck(this, MyClass);

    this.myOtherMethod = function() {};
  }

  _createClass(MyClass, [{
    key: "myMethod",
    value: function myMethod() {}
  }]);

  return MyClass;
}();

Ich verstehe, dass Pfeilfunktionen die Dinge effizienter machen, indem sie die Funktionen nicht jedes Mal neu erstellen, ähnlich wie die Bindung im Konstruktor funktioniert.

Das ist nicht wahr. Es hängt davon ab, wo genau Sie die Pfeilfunktion verwenden. Wenn Arrow function werden in der Rendermethode verwendet, dann erstellen sie eine neue Instanz everytime render heißt genauso wie how bind würde funktionieren. Betrachten Sie dieses Beispiel

<div onClick={()=>{this.onClick()}}>Previous</div>

Hier wird jedes Mal, wenn render aufgerufen wird, eine anonyme Funktion erstellt, und diese Funktion wird aufgerufen, wenn sie aufgerufen wird this.onClick.

Betrachten Sie jedoch den folgenden Fall

onClick = () => {
    console.log("Div is clicked")
}

Im obigen Fall erstellt die Pfeilfunktion die Funktion nicht jedes Mal neu, sondern bindet den Kontext an die React-Komponente als An arrow function does not have its own this; the this value of the enclosing execution context is used. einmal, wenn die Klasse instanziiert wird. Dies ist ähnlich wie binding works is constructor. Dies ist ein Teil von proposed class fields for arrow functions und es ist kein ES6-Feature,

Um zu verstehen, was Sie fragen möchten, müssen Sie wissen, dass eine Funktion ihren Kontext von dort erhält, wo sie aufgerufen wird. Überprüfen this question für mehr verständnis.

In Ihrem Fall haben Sie verwendet Arrow function definieren prevItem und erhält daher den Kontext der einschließenden React-Komponente.

prevItem = () => {
    console.log("Div is clicked")
}

render(){
    return (
         <SecondClass prevItem={this.prevItem} />
    )
}

Jetzt in seinem Kind, auch wenn Sie anrufen prevItem mit jedem benutzerdefinierten Kontext, using bind or arrow function, prevItem wenn in Eltern ausgeführt, dh Main.js erhält den Kontext seiner einschließenden React-Komponente. Und da Sie nur die prevItem-Funktion ausführen und keine Daten vom untergeordneten Element an diese übergeben möchten, schreiben Sie

<ThirdClass type="prev" onClick={()=>this.props.prevItem()} />

und

<div onClick={()=>{this.props.onClick()}}>Previous</div>

ist einfach nutzlos und trägt nur zur Auswirkung auf die Leistung bei, da neue Funktionen erstellt werden SecondClass und ThirdClass jedes Mal. Sie müssen diese Funktionen einfach nicht als Pfeilfunktion definiert haben und können einfach schreiben

<ThirdClass type="prev" onClick={this.props.prevItem} />

und

<div onClick={this.props.onClick}>Previous</div>

da es bereits im Elternteil gebunden ist.

Auch wenn Sie nun einige zusätzliche Daten an diese Funktionen von ThirdClass und SecondClass übergeben müssen, sollten Sie diese nicht direkt verwenden Arrow function oder bind in render. Schauen Sie sich diese Antwort an How to Avoid binding in Render method

  • Die Verwendung von Pfeilfunktionen ist per se nicht schlecht. Es ist vollkommen in Ordnung, Pfeilfunktionen zu verwenden render auch wenn sie nachgebaut sind. In den meisten Anwendungen wird der Leistungsunterschied nicht bemerkbar sein.

    – Divyanshu Maithani

    6. Februar 19 um 6:56 Uhr

  • @DivyanshuMaithani funktioniert der obige Code auch für funktionale Komponenten oder nur für Klassenkomponenten, müssen wir ihn erneut wie unten binden, wenn wir die funktionale Komponente SecondClass.js this verwenden .props.prevItem()} /> ThirdClass.js

    {this.props.onClick()}}>Zurück

    – Ram Somani

    14. April 21 um 11:10 Uhr


  • Mein Kommentar bezog sich auf Leistungsbedenken. Die Antwort ist etwas verwirrend, kurz gesagt, Sie sollten nur eine Klassenmethode (in Klassenkomponenten) binden müssen. Keine Notwendigkeit, eine Funktion für funktionale Komponenten zu binden, weil Sie sich nicht darum kümmern würden this Verwendung.

    – Divyanshu Maithani

    14. April 21 um 12:30 Uhr

Also dein erster Ansatz

<ThirdClass type="prev" onClick={()=>this.props.prevItem()} />

In diesem können Sie beliebige Argumente, die in ThirdClass verfügbar sind, an die Funktion prevItem übergeben. Das ist die gute Art, übergeordnete Funktionen mit Argumenten aufzurufen. So etwa

<ThirdClass type="prev" onClick={()=>this.props.prevItem(firstArgument, secondArgument)} />

Ihr zweiter Ansatz ist

<ThirdClass type="prev" onClick={this.props.prevItem} />

Bei diesem Ansatz können Sie keine ThirdClass-spezifischen Argumente übergeben.

Beide Ansätze sind richtig, es hängt nur von Ihrem Anwendungsfall ab. Sowohl der Ansatz mit der es6-Pfeilfunktion als auch in den oben genannten jeweiligen Szenarien sind richtig

1643862309 650 Korrekte Verwendung von Pfeilfunktionen in React
AmerllicA

Verwenden JavaScript Curring-Funktionsdeklaration, kann anders sein als andere Antworten, achten Sie auf die folgenden Codes:

clickHandler = someData => e => this.setState({
  stateKey: someData
});

Jetzt in JSXDu kannst schreiben:

<div onClick={this.clickHandler('someData')} />

Der clickHandler mit someData gib eine Funktion mit zurück e Argument, aber es wird nicht verwendet clickHandler Funktion. es funktioniert also gut.

Um vollständiger zu schreiben, schreiben Sie wie folgt:

clickHandler = someData => () => this.setState({
  stateKey: someData
});

Es ist nicht nötig ealso warum sollte ich es schreiben.

Die Verwendung von Pfeilen in Ihrer ursprünglichen Funktionsdefinition ermöglicht es Ihnen, die Funktion in Ihrem Konstruktor nicht zu binden.

Wenn Sie keinen Pfeil benutzt haben …

prevItem(){
  console.log("Div is clicked")
}

Dann müssten Sie einen Konstruktor erstellen und ihn dort binden …

class MyComponent extends Component {
  constructor(props) {
    super(props)
    this.prevItem = this.prevItem.bind(this)
  }

  prevItem() { ... }
}

Die Verwendung des Pfeils ist zu Beginn einfacher, da er einfach funktioniert und Sie nicht verstehen müssen, was ein Konstruktor ist, und sich nicht mit der Komplexität von beschäftigen müssen this in Javascript.

Leistungsmäßig ist es jedoch besser, den Konstruktor zu binden. Die Bind-in-Konstruktormethode erstellt eine einzelne Instanz der Funktion und verwendet sie wieder, selbst wenn die Rendermethode mehrmals aufgerufen wird.

  • Gibt es bei diesem Ansatz eine Möglichkeit, beim Aufrufen von prevItem einen Parameter hinzuzufügen. Ex: onpress={this.prevItem} aber ich rufe gerne an this.prevItem(variable)

    – gelehrt

    25. Mai 18 um 22:01 Uhr

  • Gibt es bei diesem Ansatz eine Möglichkeit, beim Aufrufen von prevItem einen Parameter hinzuzufügen. Ex: onpress={this.prevItem} aber ich rufe gerne an this.prevItem(variable)

    – gelehrt

    25. Mai 18 um 22:01 Uhr

.

750500cookie-checkKorrekte Verwendung von Pfeilfunktionen in React

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy