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?
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.
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.
Die Verwendung einer Inline-Pfeil-Funktion führt dazu, dass PureComponent
s 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
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>
);
}
}
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>
);
}
}
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
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
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:
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