React Binding Patterns: 5 approches pour gérer `this`

Le comportement de ce mot - clé de JavaScript a confondu les développeurs pendant des siècles.

Il existe au moins cinq façons de gérer ce contexte dans React. Examinons les mérites de chaque approche.

1. Utilisez React.createClass

Si vous utilisez React.createClass, React associe automatiquement toutes les fonctions à cela . Ainsi, le mot clé this est automatiquement lié à l'instance de votre composant:

// This magically works with React.createClass// because `this` is bound for you.onChange={this.handleChange}

Cependant, avec l'avènement des classes ES6, cette approche non standard de création de classes n'est pas l'avenir de React. En fait, createClass sera probablement extrait du noyau React dans une prochaine version.

2. Lier dans le rendu

Le reste de ces approches suppose que vous déclarez des composants React via des classes ES6. Si vous utilisez une classe ES6, React ne se lie plus automatiquement. Une façon de résoudre ce problème consiste à appeler bind dans render:

onChange={this.handleChange.bind(this)}

Cette approche est laconique et claire, cependant, il y a des implications sur les performances puisque la fonction est réaffectée à chaque rendu. Cela semble être un gros problème, mais les implications de cette approche sur les performances sont peu susceptibles d'être perceptibles dans la plupart des applications. Donc, exclure cela dès le départ pour des raisons de performances est une optimisation prématurée. Cela dit, voici un exemple où l'impact sur les performances de cette approche a été important.

En fin de compte, si vous rencontrez des problèmes de performances, évitez d'utiliser les fonctions de liaison ou de flèche dans le rendu.

3. Utiliser la fonction de flèche dans le rendu

Cette approche est similaire à # 2. Vous pouvez éviter de modifier ce contexte en utilisant une fonction de flèche dans le rendu:

onChange={e => this.handleChange(e)}

Cette approche a le même impact potentiel sur les performances que le n ° 2.

Les approches alternatives ci-dessous valent la peine d'être envisagées car elles offrent des performances supérieures pour un faible coût supplémentaire.

4. Lier dans le constructeur

Une façon d'éviter la liaison dans le rendu est de se lier dans le constructeur (l'autre approche est discutée dans # 5 ci-dessous).

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

C'est l'approche actuellement recommandée dans la documentation React pour «de meilleures performances dans votre application». C'est aussi l'approche que j'utilise dans «Construire des applications avec React et Redux dans ES6» sur Pluralsight.

Cependant, sur la plupart des applications, les implications en termes de performances des approches 2 et 3 ne seront pas perceptibles, de sorte que les avantages de lisibilité et de maintenance des approches 2 et 3 peuvent l'emporter sur les problèmes de performances dans de nombreuses applications.

Mais si vous êtes prêt à utiliser les fonctionnalités de l'étape 2, la dernière option ci-dessous est probablement votre meilleur pari.

5. Utiliser la fonction de flèche dans la propriété de classe

Cette technique repose sur la fonctionnalité de propriété de classe proposée. Pour utiliser cette approche, vous devez activer transform-class-properties ou activer stage-2 dans Babel.

handleChange = () => { // call this function from render // and this.whatever in here works fine. };

Cette approche présente de multiples avantages:

  1. Les fonctions de flèche adoptent la liaison this de la portée englobante (en d'autres termes, elles ne changent pas la signification de ceci), donc les choses fonctionnent automatiquement.
  2. Cela évite les problèmes de performance des approches # 2 et # 3.
  3. Cela évite la répétition dans l'approche # 4.
  4. Il est simple de refactoriser le style createClass ES5 dans ce style en convertissant les fonctions pertinentes en fonctions fléchées. En fait, il existe un moyen complètement automatisé de gérer cela à l'aide d'un codemod.

Sommaire

Cet organigramme qui résume la décision.

Voici des exemples de travail complets des 5 approches:

// Approach 1: Use React.createClass var HelloWorld = React.createClass({ getInitialState() { return { message: 'Hi' }; }, logMessage() { // this magically works because React.createClass autobinds. console.log(this.state.message); }, render() { return (  ); } }); // Approach 2: Bind in Render class HelloWorld extends React.Component { constructor(props) { super(props); this.state = { message: 'Hi' }; } logMessage() { // This works because of the bind in render below. console.log(this.state.message); } render() { return (  ); } } // Approach 3: Use Arrow Function in Render class HelloWorld extends React.Component { constructor(props) { super(props); this.state = { message: 'Hi' }; } logMessage() { // This works because of the arrow function in render below. console.log(this.state.message); } render() { return (  this.logMessage()} /> ); } } // Approach 4: Bind in Constructor class HelloWorld extends React.Component { constructor(props) { super(props); this.state = { message: 'Hi' }; this.logMessage = this.logMessage.bind(this); } logMessage() { // This works because of the bind in the constructor above. console.log(this.state.message); } render() { return (  ); } } // Approach 5: Arrow Function in Class Property class HelloWorld extends React.Component { // Note that state is a property, // so no constructor is needed in this case. state = { message: 'Hi' }; logMessage = () => { // This works because arrow funcs adopt the this binding of the enclosing scope. console.log(this.state.message); }; render() { return (  ); } }

Alors qu'est-ce que les gens préfèrent? Voici le sondage:

Comment gérez-vous la liaison dans #reactjs aujourd'hui?

Exemples: //t.co/z7OKxe39VA

- Cory House (@housecor) 18 août 2016

Avez-vous d'autres façons de gérer cela? Veuillez entrer via les commentaires.

Un grand merci à @dan_abramov, @kentcdodds et @dmosher pour leur précieuse contribution et leur critique!

Cory House est l'auteur de «Créer des applications avec React et Redux dans ES6», «Créer des applications avec React et Flux», «Clean Code: Writing Code for Humans» et de nombreux autres cours sur Pluralsight. Il est architecte logiciel chez VinSolutions, Microsoft MVP, et forme des développeurs de logiciels au niveau international sur les pratiques logicielles telles que le développement frontal et le codage propre.