wake-up-neo.com

Warum sollten JSX-Requisiten keine Pfeilfunktionen verwenden oder binden?

Ich führe mit meiner React-App Fusseln aus und erhalte folgende Fehlermeldung:

error    JSX props should not use arrow functions        react/jsx-no-bind

Und hier führe ich die Pfeilfunktion aus (in onClick):

{this.state.photos.map(tile => (
  <span key={tile.img}>
    <Checkbox
      defaultChecked={tile.checked}
      onCheck={() => this.selectPicture(tile)}
      style={{position: 'absolute', zIndex: 99, padding: 5, backgroundColor: 'rgba(255, 255, 255, 0.72)'}}
    />
    <GridTile
      title={tile.title}
      subtitle={<span>by <b>{tile.author}</b></span>}
      actionIcon={<IconButton onClick={() => this.handleDelete(tile)}><Delete color="white"/></IconButton>}
    >
      <img onClick={() => this.handleOpen(tile.img)} src={tile.img} style={{cursor: 'pointer'}}/>
    </GridTile>
  </span>
))}

Ist dies eine schlechte Praxis, die vermieden werden sollte? Und wie geht es am besten?

71
KadoBOT

Warum sollten Sie Inline-Pfeilfunktionen in JSX-Requisiten nicht verwenden?

Die Verwendung von Pfeilfunktionen oder das Binden in JSX ist eine schlechte Praxis, die die Leistung beeinträchtigt, da die Funktion bei jedem Rendern neu erstellt wird.

  1. Immer wenn eine Funktion erstellt wird, wird die vorhergehende Funktion Müll gesammelt. Das erneute Rendern vieler Elemente kann in Animationen zu Schwankungen führen.

  2. Die Verwendung einer Inline-Pfeil-Funktion führt dazu, dass PureComponents und Komponenten, die shallowCompare in der shouldComponentUpdate-Methode verwenden, trotzdem erneut gerendert werden. Da die Pfeilfunktion prop jedes Mal neu erstellt wird, wird sie vom flachen Vergleich als Änderung an einer Requisite identifiziert und die Komponente wird erneut gerendert.

Wie Sie in den folgenden zwei Beispielen sehen können - Wenn wir die Inline-Pfeil-Funktion verwenden, wird die <Button>-Komponente jedes Mal erneut gerendert (die Konsole zeigt den Text "Renderschaltfläche").

Beispiel 1 - PureComponent ohne Inline-Handler

class Button extends React.PureComponent {
  render() {
    const { onClick } = this.props;
    
    console.log('render button');
    
    return (
      <button onClick={ onClick }>Click</button>
    );
  }
}

class Parent extends React.Component {
  state = {
    counter: 0
  }
  
  onClick = () => this.setState((prevState) => ({
    counter: prevState.counter + 1
  }));
  
  render() {
    const { counter } = this.state;
    
    return (
      <div>
        <Button onClick={ this.onClick } />
        <div>{ counter }</div>
      </div>
    );
  }
}

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Beispiel 2 - PureComponent mit Inline-Handler

class Button extends React.PureComponent {
  render() {
    const { onClick } = this.props;
    
    console.log('render button');
    
    return (
      <button onClick={ onClick }>Click</button>
    );
  }
}

class Parent extends React.Component {
  state = {
    counter: 0
  }
  
  render() {
    const { counter } = this.state;
    
    return (
      <div>
        <Button onClick={ () => this.setState((prevState) => ({
          counter: prevState.counter + 1
        })) } />
        <div>{ counter }</div>
      </div>
    );
  }
}

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Bindungsmethoden an this ohne Inlining von Pfeilfunktionen

  1. Methode manuell im Konstruktor binden:

    class Button extends React.Component {
      constructor(props, context) {
        super(props, context);
    
        this.cb = this.cb.bind(this);
      }
    
      cb() {
    
      }
    
      render() {
        return (
          <button onClick={ this.cb }>Click</button>
        );
      }
    }
    
  2. Binden einer Methode mithilfe der Vorschlag-Klassen-Felder mit einer Pfeilfunktion. Da dies ein Vorschlag für Stufe 3 ist, müssen Sie die Stufe - 3 - Voreinstellung oder die Class - Eigenschaftsumwandlung zu Ihrer Babel - Konfiguration hinzufügen.

    class Button extends React.Component {
      cb = () => { // the class property is initialized with an arrow function that binds this to the class
    
      }
    
      render() {
        return (
          <button onClick={ this.cb }>Click</button>
        );
      }
    }
    
126
Ori Drori

Dies liegt daran, dass eine Pfeilfunktion anscheinend eine neue Instanz der Funktion in jedem Render erstellt, wenn sie in einer JSX-Eigenschaft verwendet wird. Dies kann zu einer enormen Belastung für den Garbage Collector führen und den Browser auch daran hindern, "heiße Pfade" zu optimieren, da Funktionen weggeworfen und nicht wiederverwendet werden.

Die vollständige Erklärung und weitere Informationen finden Sie unter https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md

8

Um zu vermeiden, dass neue Funktionen mit denselben Argumenten erstellt werden, können Sie das Ergebnis der Funktionsbindung merken. Hier ist ein einfaches Dienstprogramm namens memobind: https://github.com/supnate/memobind

4
supNate

Sie können Pfeilfunktionen mit React-Cached-Handler Library verwenden, ohne sich Gedanken über die Leistung beim erneuten Rendern machen zu müssen:

Hinweis: Intern werden Ihre Pfeilfunktionen durch die angegebene Taste zwischengespeichert, sodass Sie sich keine Sorgen um ein erneutes Rendern machen müssen!

render() {

  return <div>
  {
        this.props.photos.map(photo=>
          <Photo key={photo.url}
            onClick={this.handler(photo.url, (url) => { 
                 console.log(url) })}
          />)
   }
 </div>

}

Weitere Funktionen:

  • Benannte Handler
  • Behandeln Sie Ereignisse mit Pfeilfunktionen
  • Zugriff auf den Schlüssel, benutzerdefinierte Argumente und das ursprüngliche Ereignis
  • Leistung beim Rendern von Komponenten
  • Benutzerdefinierter Kontext für Handler
0
Ghominejad

Die Verwendung solcher Inline-Funktionen ist vollkommen in Ordnung. Die Fusselregel ist veraltet. 

Diese Regel stammt aus einer Zeit, in der Pfeilfunktionen nicht so üblich waren und Leute .bind (this) verwendeten, was früher langsam war. Das Leistungsproblem wurde in Chrome 49 behoben.

Achten Sie darauf, dass Sie Inline-Funktionen nicht als Requisiten an eine untergeordnete Komponente übergeben.

Ryan Florence, der Autor von React Router, hat dazu ein großartiges Stück geschrieben:

https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578

0
sbaechler