De nos jours, React est l’une des bibliothèques JavaScript les plus populaires. Elle peut être utilisée pour créer des applications dynamiques et responsives, permet de meilleures performances et peut être facilement étendue. La logique sous-jacente est basée sur des composants qui peuvent être réutilisés dans différents contextes, ce qui réduit la nécessité d’écrire plusieurs fois le même code. En bref, avec React, vous pouvez créer des applications efficaces et puissantes.

Il n’y a donc jamais eu de meilleur moment pour apprendre à créer des applications React.

Cependant, sans une solide compréhension de certaines fonctionnalités clés de JavaScript, la création d’applications React pourrait s’avérer difficile, voire impossible.

C’est pourquoi nous avons compilé une liste de fonctionnalités et de concepts JavaScript que vous devez connaître avant de commencer à utiliser React. Mieux vous comprendrez ces concepts, plus il vous sera facile de créer des applications React professionnelles.

Ceci étant dit, voici ce que nous allons aborder dans cet article :

JavaScript et ECMAScript

JavaScript est un langage de script populaire utilisé avec HTML et CSS pour créer des pages web dynamiques. Alors que le HTML est utilisé pour créer la structure d’une page web et le CSS pour créer le style et la mise en page de ses éléments, JavaScript est le langage utilisé pour ajouter du comportement à la page, c’est-à-dire pour créer de la fonctionnalité et de l’interactivité.

Le langage a depuis été adopté par les principaux navigateurs et un document a été rédigé pour décrire la manière dont JavaScript était censé fonctionner : la norme ECMAScript.

Depuis 2015, une mise à jour de la norme ECMAScript est publiée chaque année, ce qui signifie que de nouvelles fonctionnalités sont ajoutées à JavaScript chaque année.

ECMAScript 2015 était la sixième version de la norme et est donc également connue sous le nom de ES6. Les versions suivantes sont marquées par une progression, de sorte que nous appelons ECMAScript 2016 ES7, ECMAScript 2017 ES8, et ainsi de suite.

En raison de la fréquence à laquelle de nouvelles fonctionnalités sont ajoutées à la norme, certaines d’entre elles peuvent ne pas être prises en charge par tous les navigateurs. Comment pouvez-vous donc vous assurer que les dernières fonctionnalités JavaScript que vous avez ajoutées à votre application JS fonctionneront comme prévu dans tous les navigateurs web ?

Trois possibilités s’offrent à vous :

  1. Attendre que tous les principaux navigateurs prennent en charge les nouvelles fonctionnalités. Mais si vous avez absolument besoin de cette nouvelle fonctionnalité JS pour votre application, cette option n’est pas envisageable.
  2. Utilisez un Polyfill, qui est « un morceau de code (généralement JavaScript sur le web) utilisé pour fournir des fonctionnalités modernes sur des navigateurs plus anciens qui ne les prennent pas en charge de manière native » (voir également les documents web de mdn).
  3. Utilisez un transpileur JavaScript tel que Babel ou Traceur, qui convertit le code ECMAScript 2015+ en une version JavaScript supportée par tous les navigateurs.

Déclarations et expressions

Comprendre la différence entre les déclarations et les expressions est essentiel lors de la construction d’applications React. Revenons donc un instant sur les concepts de base de la programmation.

Un programme informatique est une liste d’instructions à exécuter par un ordinateur. Ces instructions sont appelées instructions.

Contrairement aux instructions, les expressions sont des fragments de code qui produisent une valeur. Dans une instruction, une expression est une partie qui renvoie une valeur et nous la voyons généralement à droite d’un signe égal.

Alors que :

Les déclarations JavaScript peuvent être des blocs ou des lignes de code qui se terminent généralement par des points-virgules ou sont placées entre crochets.

Voici un exemple simple de déclaration en JavaScript :

document.getElementById("hello").innerHTML = "Hello World!";

La déclaration ci-dessus écrit "Hello World!" dans un élément DOM avec id="hello".

Comme nous l’avons déjà mentionné, les expressions produisent une valeur ou sont elles-mêmes une valeur. Considérez l’exemple suivant :

msg = document.getElementById("hello").value;

document.getElementById("hello").value est une expression car elle renvoie une valeur.

Un autre exemple devrait aider à clarifier la différence entre les expressions et les déclarations :

const msg = "Hello World!";
function sayHello( msg ) {
	console.log( msg );
}

Dans l’exemple ci-dessus,

  • la première ligne est une instruction, où "Hello World!" est une expression,
  • la déclaration de la fonction est une instruction, où le paramètre msg passé à la fonction est une expression,
  • la ligne qui imprime le affiche dans la console est une instruction, où le paramètre msg est à nouveau une expression.

Pourquoi les expressions sont importantes dans React

Lorsque vous construisez une application React, vous pouvez injecter des expressions JavaScript dans votre code JSX. Par exemple, vous pouvez passer une variable, écrire un gestionnaire d’événement ou une condition. Pour cela, vous devez inclure votre code JS entre crochets.

Par exemple, vous pouvez passer une variable :

const Message = () => {
	const name = "Carlo";
	return <p>Welcome {name}!</p>;
}

En bref, les crochets curly indiquent à votre transpondeur de traiter le code entre crochets comme du code JS. Tout ce qui se trouve avant la balise ouvrante <p> et après la balise fermante </p> est du code JavaScript normal. Tout ce qui se trouve à l’intérieur des balises d’ouverture <p> et de fermeture </p> est traité comme du code JSX.

Voici un autre exemple :

const Message = () => {	
	const name = "Ann";
	const heading = <h3>Welcome {name}</h3>;
	return (
		<div>
			{heading}
			<p>This is your dashboard.</p>
		</div>
	);
}

Vous pouvez également transmettre un objet :

render(){			
	const person = {
		name: 'Carlo',
		avatar: 'https://en.gravatar.com/userimage/954861/fc68a728946aac04f8531c3a8742ac22',
		description: 'Content Writer'
	}

	return (
		<div>
			<h2>Welcome {person.name}</h2>
			<img
				className="card"
				src={person.avatar}
				alt={person.name}
			/>
			<p>Description: {person.description}.</p>
		</div>
	);
}

Vous trouverez ci-dessous un exemple plus complet :

render(){
	const person = {
		name: 'Carlo',
		avatar: 'https://en.gravatar.com/userimage/954861/fc68a728946aac04f8531c3a8742ac22?size=original',
		description: 'Content Writer',
		theme: {
			boxShadow: '0 4px 8px 0 rgba(0,0,0,0.2)', width: '200px'
		}
	}

	return (
		<div style={person.theme}>
			<img
				src={person.avatar}
				alt={person.name}
				style={ { width: '100%' } }
			/>
			<div style={ { padding: '2px 16px' } }>
				<h3>{person.name}</h3>
				<p>{person.description}.</p>
			</div>
		</div>
	);
}

Remarquez les doubles crochets dans les attributs style des éléments img et div. Nous avons utilisé des doubles crochets pour transmettre deux objets contenant des styles de carte et d’image.

Un exemple de carte construit avec React
Un exemple de carte construit avec React

Vous avez dû remarquer que dans tous les exemples ci-dessus, nous avons inclus des expressions JavaScript dans JSX.

L’immutabilité dans React

La mutabilité et l’immutabilité sont deux concepts clés de la programmation orientée objet et fonctionnelle.

L’immutabilité signifie qu’une valeur ne peut pas être modifiée après sa création. La mutabilité signifie, bien sûr, le contraire.

En Javascript, les valeurs primitives sont immuables, ce qui signifie qu’une fois qu’une valeur primitive est créée, elle ne peut plus être modifiée. A l’inverse, les tableaux et les objets sont mutables car leurs propriétés et leurs éléments peuvent être modifiés sans réaffectation d’une nouvelle valeur.

Plusieurs raisons justifient l’utilisation d’objets immuables en JavaScript :

  • Amélioration des performances
  • Réduction de la consommation de mémoire
  • Sécurité des threads
  • Codage et débogage plus faciles

Suivant le modèle de l’immutabilité, une fois qu’une variable ou un objet est assigné, il ne peut pas être réassigné ou modifié. Lorsque vous devez modifier des données, vous devez en créer une copie et en modifier le contenu, en laissant le contenu original inchangé.

L’immuabilité est également un concept clé de React.

La documentation de React indique que

L’état d’un composant de classe est disponible à l’adresse this.state. Le champ state doit être un objet. Ne modifiez pas l’état directement. Si vous souhaitez modifier l’état, appelez setState avec le nouvel état

.
Chaque fois que l’état d’un composant change, React calcule s’il faut rendre à nouveau le composant et mettre à jour le DOM virtuel. Si React n’avait pas de trace de l’état précédent, il ne pourrait pas déterminer s’il faut rendre le composant ou non. La documentation de React en donne un excellent exemple.

Quelles fonctionnalités JavaScript pouvons-nous utiliser pour garantir l’immuabilité de l’objet state dans React ? Découvrons-le !

Déclarer des variables

Vous avez trois façons de déclarer une variable en JavaScript : var, let, et const.

L’instructionvar existe depuis le début de JavaScript. Elle est utilisée pour déclarer une variable à portée de fonction ou à portée globale, en l’initialisant éventuellement à une valeur.

Lorsque vous déclarez une variable à l’aide de var, vous pouvez la redéclarer et la mettre à jour à la fois dans la portée globale et locale. Le code suivant est autorisé :

// Declare a variable
var msg = "Hello!";

// Redeclare the same variable
var msg = "Goodbye!"

// Update the variable
msg = "Hello again!"

les déclarations var  sont traitées avant l’exécution de tout code. Par conséquent, déclarer une variable n’importe où dans le code équivaut à la déclarer au début. Ce comportement est appelé hoisting.

Il convient de noter que seule la déclaration de la variable est hissée, et non l’initialisation, qui n’a lieu que lorsque le flux de contrôle atteint l’instruction d’affectation. Jusqu’à ce moment, la variable est undefined:

console.log(msg); // undefined
var msg = "Hello!";
console.log(msg); // Hello!

La portée d’une variable var déclarée dans une fonction JS est l’ensemble du corps de cette fonction.

Cela signifie que la variable n’est pas définie au niveau du bloc, mais au niveau de la fonction entière. Cela entraîne un certain nombre de problèmes qui peuvent rendre votre code JavaScript bogué et difficile à maintenir.

Pour résoudre ces problèmes, ES6 a introduit le mot-clélet.

La déclaration let déclare une variable locale à l’échelle d’un bloc, en l’initialisant éventuellement à une valeur.

Quels sont les avantages de let par rapport à var? En voici quelques-uns :

  • Le mot-clé let déclare une variable dans la portée d’une instruction de bloc, alors que vardéclare une variable globalement ou localement dans une fonction entière, sans tenir compte de la portée du bloc.
  • Les variables globales let ne sont pas des propriétés de l’objet window . Vous ne pouvez pas y accéder avec window.variableName.
  • let n’est accessible qu’après leur déclaration. La variable n’est pas initialisée avant que le flux de contrôle n’atteigne la ligne de code où elle est déclarée (les déclarations let ne sont pas groupées).
  • Redéclarer une variable avec let provoque une erreur SyntaxError.

Étant donné que les variables déclarées à l’aide de var ne peuvent pas faire l’objet d’un contrôle par bloc, si vous définissez une variable à l’aide de var dans une boucle ou à l’intérieur d’une instruction if, il est possible d’y accéder depuis l’extérieur du bloc, ce qui peut entraîner des bogues dans le code.

Le code du premier exemple est exécuté sans erreur. Remplacez maintenant var par let dans le bloc de code ci-dessus :

console.log(msg);
let msg = "Hello!";
console.log(msg);

Dans le deuxième exemple, l’utilisation de let au lieu de var produit un Uncaught ReferenceError:

Uncaught ReferenceError dans Chrome
Uncaught ReferenceError dans Chrome

ES6 introduit également un troisième mot-clé : const.

const est assez similaire à let, mais avec une différence essentielle :

Considérez l’exemple suivant :

const MAX_VALUE = 1000;
MAX_VALUE = 2000;

Le code ci-dessus générerait l’erreur de type suivante :

<em>Uncaught TypeError : Affectation à une variable constante</em> dans Google Chrome
Uncaught TypeError : Affectation à une variable constante dans Google Chrome

En outre :

Déclarer un const sans lui donner de valeur provoquerait le problème suivant : SyntaxError (voir aussi ES6 In Depth : let et const) :

Uncaught SyntaxError : Initialisateur manquant dans la déclaration const dans Chrome
Uncaught SyntaxError : Initialisateur manquant dans la déclaration const dans Chrome

Mais si une constante est un tableau ou un objet, vous pouvez modifier les propriétés ou les éléments de ce tableau ou de cet objet.

Par exemple, vous pouvez modifier, ajouter et supprimer des éléments d’un tableau :

// Declare a constant array
const cities = ["London", "New York", "Sydney"];

// Change an item
cities[0] = "Madrid";

// Add an item
cities.push("Paris");

// Remove an item
cities.pop();

console.log(cities);

// Array(3)
// 0: "Madrid"
// 1: "New York"
// 2: "Sydney"

Mais vous n’êtes pas autorisé à réaffecter le tableau :

const cities = ["London", "New York", "Sydney"];

cities = ["Athens", "Barcelona", "Naples"];

Le code ci-dessus entraînerait une erreur de type (TypeError).

Uncaught TypeError : Affectation à une variable constante dans Chrome
Uncaught TypeError : Affectation à une variable constante dans Chrome

Vous pouvez ajouter, réaffecter et supprimer des propriétés et des méthodes d’objets :

// Declare a constant obj
const post = {
	id: 1,
	name: 'JavaScript is awesome',
	excerpt: 'JavaScript is an awesome scripting language',
	content: 'JavaScript is a scripting language that enables you to create dynamically updating content.'
};

// add a new property
post.slug = "javascript-is-awesome";

// Reassign property
post.id = 5;

// Delete a property
delete post.excerpt;

console.log(post);

// {id: 5, name: 'JavaScript is awesome', content: 'JavaScript is a scripting language that enables you to create dynamically updating content.', slug: 'javascript-is-awesome'}

Mais vous n’êtes pas autorisé à réaffecter l’objet lui-même. Le code suivant passerait par un Uncaught TypeError:

// Declare a constant obj
const post = {
	id: 1,
	name: 'JavaScript is awesome',
	excerpt: 'JavaScript is an awesome scripting language'
};

post = {
	id: 1,
	name: 'React is powerful',
	excerpt: 'React lets you build user interfaces'
};

Object.freeze()

Nous sommes maintenant d’accord sur le fait que l’utilisation de const ne garantit pas toujours une forte immutabilité (en particulier lorsque vous travaillez avec des objets et des tableaux). Alors, comment pouvez-vous mettre en œuvre le modèle d’immutabilité dans vos applications React ?

Tout d’abord, lorsque vous souhaitez empêcher la modification des éléments d’un tableau ou des propriétés d’un objet, vous pouvez utiliser la méthode statique Object.freeze().

Le gel d’un objet empêche les extensions et rend les propriétés existantes non inscriptibles et non configurables. Un objet gelé ne peut plus être modifié : de nouvelles propriétés ne peuvent pas être ajoutées, les propriétés existantes ne peuvent pas être supprimées, leur énumérabilité, leur configurabilité, leur inscriptibilité ou leur valeur ne peuvent pas être modifiées, et le prototype de l’objet ne peut pas être réattribué. freeze() renvoie le même objet que celui qui lui a été transmis.

Toute tentative d’ajout, de modification ou de suppression d’une propriété échouera, soit silencieusement, soit en lançant un message TypeError, le plus souvent en mode strict.

Vous pouvez utiliser Object.freeze() de cette manière :

'use strict'
// Declare a constant obj
const post = {
	id: 1,
	name: 'JavaScript is awesome',
	excerpt: 'JavaScript is an awesome scripting language'
};
// Freeze the object
Object.freeze(post);

Si vous essayez maintenant d’ajouter une propriété, vous recevrez un Uncaught TypeError:

// Add a new property
post.slug = "javascript-is-awesome"; // Uncaught TypeError
Uncaught TypeError : can't define property
Uncaught TypeError : can’t define property « slug » : L ‘objet n’est pas extensible dans Firefox

Lorsque vous essayez de réaffecter une propriété, vous obtenez un autre type de TypeError:

// Reassign property
post.id = 5; // Uncaught TypeError
La réaffectation d'une propriété en lecture seule provoque une erreur de type (Uncaught TypeError)
La réaffectation d’une propriété en lecture seule provoque une erreur de type (Uncaught TypeError)
Uncaught TypeError : Cannot assign to read only property 'id' of object '#<Object>' dans Google Chrome
Uncaught TypeError : Cannot assign to read only property ‘id’ of object ‘#<Object>’ dans Google Chrome

Vous pouvez également essayer de supprimer une propriété. Le résultat sera un autre TypeError:

// Delete a property
delete post.excerpt; // Uncaught TypeError
Uncaught TypeError : la propriété
Uncaught TypeError : la propriété « excerpt » n’est pas configurable et ne peut pas être supprimée dans Firefox

Libellés de modèles

Lorsque vous devez combiner des chaînes de caractères avec la sortie d’expressions en JavaScript, vous utilisez généralement l’opérateur d’addition +. Cependant, vous pouvez également utiliser une fonctionnalité JavaScript qui vous permet d’inclure des expressions dans des chaînes sans utiliser l’opérateur d’addition : Template Literals (littéral de modèle).

Les Template Literals sont un type particulier de chaînes de caractères délimitées par des caractères backtick (`).

Dans les Template Literals, vous pouvez inclure des espaces réservés, qui sont des expressions intégrées délimitées par un dollar et placées entre crochets.

Voici un exemple :

const align = 'left';
console.log(`This string is ${ align }-aligned`);

Les chaînes et les caractères génériques sont transmis à une fonction par défaut qui effectue une interpolation de chaîne pour remplacer les caractères génériques et concaténer les parties en une seule chaîne. Vous pouvez également remplacer la fonction par défaut par une fonction personnalisée.

Vous pouvez utiliser les modèles littéraux pour :

Chaînes à plusieurs lignes: les caractères de retour à la ligne font partie du littéral de modèle.

console.log(`Twinkle, twinkle, little bat!
How I wonder what you’re at!`);

Interpolation de chaînes: Sans les littéraux de modèle, vous ne pouvez utiliser que l’opérateur d’addition pour combiner la sortie d’expressions avec des chaînes de caractères. Voir l’exemple suivant :

const a = 3;
const b = 7;
console.log("The result of " + a + " + " + b + " is " + (a + b));

C’est un peu déroutant, n’est-ce pas ? Mais vous pouvez écrire ce code d’une manière plus lisible et plus facile à maintenir en utilisant les modèles littéraux :

const a = 3;
const b = 7;
console.log(`The result of ${ a } + ${ b } is ${ a + b }`);

Mais gardez à l’esprit qu’il y a une différence entre les deux syntaxes:

Les littéraux de modèle se prêtent à plusieurs utilisations. Dans l’exemple suivant, nous utilisons un opérateur ternaire pour attribuer une valeur à un attribut class.

const page = 'archive';
console.log(`class=${ page === 'archive' ? 'archive' : 'single' }`);

Ci-dessous, nous effectuons un simple calcul :

const price = 100;
const VAT = 0.22;

console.log(`Total price: ${ (price * (1 + VAT)).toFixed(2) }`);

Il est également possible d’imbriquer les Template Literals en les incluant à l’intérieur d’un espace réservé ${expression} (mais utilisez les modèles imbriqués avec prudence car les structures de chaînes complexes peuvent être difficiles à lire et à maintenir).

Modèles balisés : Comme nous l’avons mentionné ci-dessus, il est également possible de définir une fonction personnalisée pour effectuer une concaténation de chaînes. Ce type de modèle littéral est appelé modèle balisé.

Les balises vous permettent d’analyser les modèles littéraux à l’aide d’une fonction. Le premier argument d’une fonction de balise contient un tableau de valeurs de chaîne. Les autres arguments sont liés aux expressions.

Les balises vous permettent d’analyser les littéraux du modèle à l’aide d’une fonction personnalisée. Le premier argument de cette fonction est un tableau de chaînes de caractères incluses dans le modèle littéral, les autres arguments étant les expressions.

Vous pouvez créer une fonction personnalisée pour effectuer n’importe quelle opération sur les arguments du modèle et renvoyer la chaîne manipulée. Voici un exemple très basique de modèle balisé:

const name = "Carlo";
const role = "student";
const organization = "North Pole University";
const age = 25;

function customFunc(strings, ...tags) {
	console.log(strings); // ['My name is ', ", I'm ", ', and I am ', ' at ', '', raw: Array(5)]
	console.log(tags); // ['Carlo', 25, 'student', 'North Pole University']
	let string = '';
	for ( let i = 0; i < strings.length - 1; i++ ){
		console.log(i + "" + strings[i] + "" + tags[i]);
		string += strings[i] + tags[i];
	}
	return string.toUpperCase();
}

const output = customFunc`My name is ${name}, I'm ${age}, and I am ${role} at ${organization}`;
console.log(output);

Le code ci-dessus imprime les éléments des tableaux strings et tags, puis met en majuscules les caractères de la chaîne avant d’imprimer la sortie dans la console du navigateur.

Fonctions fléchées

Les fonctions fléchées sont une alternative aux fonctions anonymes (fonctions sans nom) en JavaScript, mais avec quelques différences et limitations.

Les déclarations suivantes sont toutes des exemples valables de fonctions fléchées :

// Arrow function without parameters
const myFunction = () => expression;

// Arrow function with one parameter
const myFunction = param => expression;

// Arrow function with one parameter
const myFunction = (param) => expression;

// Arrow function with more parameters
const myFunction = (param1, param2) => expression;

// Arrow function without parameters
const myFunction = () => {
	statements
}

// Arrow function with one parameter
const myFunction = param => {
	statements
}

// Arrow function with more parameters
const myFunction = (param1, param2) => {
	statements
}

Vous pouvez omettre les crochets ronds si vous ne passez qu’un seul paramètre à la fonction. Si vous passez deux paramètres ou plus, vous devez les mettre entre parenthèses. Voici un exemple :

const render = ( id, title, category ) => `${id}: ${title} - ${category}`;
console.log( render ( 5, 'Hello World!', "JavaScript" ) );

Flèche à une ligne Les fonctions renvoient une valeur par défaut. Si vous utilisez la syntaxe à plusieurs lignes, vous devrez renvoyer manuellement une valeur :

const render = ( id, title, category ) => {
	console.log( `Post title: ${ title }` );
	return `${ id }: ${ title } - ${ category }`;
}
console.log( `Post details: ${ render ( 5, 'Hello World!', "JavaScript" ) }` );

L’une des principales différences entre les fonctions normales et les fonctions Arrow est que les fonctions Arrow n’ont pas leurs propres liens avec le mot-clé this. Si vous essayez d’utiliser this dans une fonction Arrow, il sortira de la portée de la fonction.

Pour une description plus approfondie des fonctions Arrow et des exemples d’utilisation, lisez également la documentation web mdn.

Classes

Les classes en JavaScript sont un type spécial de fonction pour créer des objets qui utilisent le mécanisme d’héritage prototypique.

D’après la documentation web mdn,

En matière d’héritage, JavaScript n’a qu’une seule construction : les objets. Chaque objet possède une propriété privée qui contient un lien vers un autre objet appelé son prototype. Cet objet prototype a son propre prototype, et ainsi de suite jusqu’à ce qu’un objet soit atteint avec null comme prototype.

Comme pour les fonctions, vous avez deux façons de définir une classe :

  • Une expression de classe
  • Une déclaration de classe

Vous pouvez utiliser le mot-clé class pour définir une classe à l’intérieur d’une expression, comme le montre l’exemple suivant :

const Circle = class {
	constructor(radius) {
		this.radius = Number(radius);
	}
	area() {
		return Math.PI * Math.pow(this.radius, 2);
	}
	circumference() {
		return Math.PI * this.radius * 2;
	}
}
console.log('Circumference: ' + new Circle(10).circumference()); // 62.83185307179586
console.log('Area: ' + new Circle(10).area()); // 314.1592653589793

Une classe a un corps, c’est-à-dire le code inclus dans les accolades. Vous y définirez le constructeur et les méthodes, également appelés membres de la classe. Le corps de la classe est exécuté en mode strict même sans utiliser la directive 'strict mode'.

La méthode constructor est utilisée pour créer et initialiser un objet créé avec une classe et est automatiquement exécutée lorsque la classe est instanciée. Si vous ne définissez pas de méthode de construction dans votre classe, JavaScript utilisera automatiquement un constructeur par défaut.

Une classe peut être étendue à l’aide du mot-clé extends.

class Book {
	constructor(title, author) {
		this.booktitle = title;
		this.authorname = author;
	}
	present() {
		return this.booktitle + ' is a great book from ' + this.authorname;
	}
}

class BookDetails extends Book {
	constructor(title, author, cat) {
		super(title, author);
		this.category = cat;
	}
	show() {
		return this.present() + ', it is a ' + this.category + ' book';
	}
}

const bookInfo = new BookDetails("The Fellowship of the Ring", "J. R. R. Tolkien", "Fantasy");
console.log(bookInfo.show());

Un constructeur peut utiliser le mot-clé super pour appeler le constructeur parent. Si vous passez un argument à la méthode super(), cet argument sera également disponible dans la classe du constructeur parent.

Pour une étude plus approfondie des classes JavaScript et plusieurs exemples d’utilisation, consultez également la documentation web de mdn.

Les classes sont souvent utilisées pour créer des composants React. En général, vous ne créerez pas vos propres classes, mais vous étendrez les classes React intégrées.

Toutes les classes de React ont une méthode render() qui renvoie un élément React :

class Animal extends React.Component {
	render() {
		return <h2>Hey, I am a {this.props.name}!</h2>;
	}
}

Dans l’exemple ci-dessus, Animal est un composant de classe. Gardez à l’esprit que

  • Le nom du composant doit commencer par une majuscule
  • Le composant doit inclure l’expression extends React.Component. Celle-ci donne accès aux méthodes du composant React.Component.
  • La méthode render() renvoie le HTML et est obligatoire.

Une fois que vous avez créé votre composant de classe, vous pouvez rendre le HTML sur la page :

const root = ReactDOM.createRoot(document.getElementById('root'));
const element = <Animal name="Rabbit" />;
root.render(element);

L’image ci-dessous montre le résultat sur la page (vous pouvez le voir en action sur CodePen).

Un simple composant de classe React
Un simple composant de classe React

Notez cependant que l’utilisation de composants de classe dans React n’est pas recommandée et qu’il est préférable de définir les composants comme des fonctions.

Le mot-clé « this »

En JavaScript, le mot-clé this est un espace générique généralement utilisé à l’intérieur d’objets, de classes et de fonctions, et il fait référence à différents éléments en fonction du contexte ou de la portée.

Le mot-clé this peut être utilisé dans la portée globale. Si vous tapez this dans la console de votre navigateur, vous obtenez :

Window {window: Window, self: Window, document: document, name: '', location: Location, ...}

Vous pouvez accéder à toutes les méthodes et propriétés de l’objet Window. Ainsi, si vous exécutez this.location dans la console de votre navigateur, vous obtiendrez le résultat suivant :

Location {ancestorOrigins: DOMStringList, href: 'https://kinsta.com/', origin: 'https://kinsta.com', protocol: 'https:', host: 'kinsta.com', ...}

Lorsque vous utilisez this dans un objet, il fait référence à l’objet lui-même. Ainsi, vous pouvez faire référence aux valeurs d’un objet dans les méthodes de l’objet lui-même :

const post = { 
	id: 5,
	getSlug: function(){
		return `post-${this.id}`;
	},
	title: 'Awesome post', 
	category: 'JavaScript' 
};
console.log( post.getSlug );

Essayons maintenant d’utiliser this dans une fonction :

const useThis = function () {
	return this;
}
console.log( useThis() );

Si vous n’êtes pas en mode strict, vous obtiendrez :

Window {window: Window, self: Window, document: document, name: '', location: Location, ...}

Mais si vous invoquez le mode strict, vous obtiendrez un résultat différent :

const doSomething = function () {
	'use strict';
	return this;
}
console.log( doSomething() );

Dans ce cas, la fonction renvoie undefined. C’est parce que this dans une fonction fait référence à sa valeur explicite.

Comment définir explicitement this dans une fonction ?

Tout d’abord, vous pouvez attribuer manuellement des propriétés et des méthodes à la fonction :

function doSomething( post ) {
	this.id = post.id;
	this.title = post.title;
	console.log( `${this.id} - ${this.title}` );
}
new doSomething( { id: 5, title: 'Awesome post' } );

Mais vous pouvez également utiliser les méthodes call, apply, et bind, ainsi que les fonctions fléchées.

const doSomething = function() {
	console.log( `${this.id} - ${this.title}` );
}
doSomething.call( { id: 5, title: 'Awesome post' } );

La méthode call() peut être utilisée sur n’importe quelle fonction et fait exactement ce qu’elle dit : elle appelle la fonction.

En outre, call() accepte tout autre paramètre défini dans la fonction :

const doSomething = function( cat ) {
	console.log( `${this.id} - ${this.title} - Category: ${cat}` );
}
doSomething.call( { id: 5, title: 'Awesome post' }, 'JavaScript' );
const doSomething = function( cat1, cat2 ) {
	console.log( `${this.id} - ${this.title} - Categories: ${cat1}, ${cat2}` );
}
doSomething.apply( { id: 5, title: 'Awesome post' }, ['JavaScript', 'React'] );
const post = { id: 5, title: 'Awesome post', category: 'JavaScript' };
const doSomething = function() {
	return `${this.id} - ${this.title} - ${this.category}`;
}
const bindRender = doSomething.bind( post );
console.log( bindRender() );

Une alternative aux options discutées ci-dessus est l’utilisation de fonctions fléchées.

Les expressions de fonctions fléchées ne doivent être utilisées que pour les fonctions qui ne sont pas des méthodes, car elles n’ont pas leur propre this.

Les fonctions fléchées sont donc particulièrement utiles pour les gestionnaires d’événements.

En effet, « lorsque le code est appelé à partir d’un attribut de gestionnaire d’événement en ligne, son adresse this est définie sur l’élément DOM sur lequel l’écouteur est placé » (voir la documentation web de mdn).

Mais les choses changent avec les fonctions fléchées car…

… les fonctions fléchées établissent this en fonction de la portée dans laquelle la fonction fléchée est définie, et la valeur this ne change pas en fonction de la manière dont la fonction est invoquée.

Lier « this » à des gestionnaires d’événements dans React

Avec React, vous disposez de plusieurs moyens pour vous assurer que le gestionnaire d’événements ne perd pas son contexte :

1. En utilisant bind() à l’intérieur de la méthode de rendu :

import React, { Component } from 'react';
class MyComponent extends Component {
	state = { message: 'Hello World!' };

	showMessage(){
		console.log( 'This refers to: ', this );
		console.log( 'The message is: ', this.state.message );
	}

	render(){
		return( <button onClick={ this.showMessage.bind( this ) }>Show message from state!</button> );
	}
}
export default MyComponent;

2. Lier le contexte au gestionnaire d’événements dans le constructeur :

import React, { Component } from 'react';
class MyComponent extends Component {
	state = { message: 'Hello World!' };

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

	showMessage(){
		console.log( 'This refers to: ', this );
		console.log( 'The message is: ', this.state.message );
	}

	render(){
		return( <button onClick={ this.showMessage }>Show message from state!</button> );
	}
}
export default MyComponent;

3. Définissez le gestionnaire d’événements à l’aide de fonctions fléchées :

import React, { Component } from 'react';
class MyComponent extends Component {
	state = { message: 'Hello World!' };

	showMessage = () => {
		console.log( 'This refers to: ', this );
		console.log( 'The message is: ', this.state.message );
	}

	render(){
		return( <button onClick={this.showMessage}>Show message from state!</button> );
	}
}
export default MyComponent;

4. Utiliser les fonctions fléchées dans la méthode de rendu :

import React, { Component } from 'react';
class MyComponent extends Component {
	state = { message: 'Hello World!' };

	showMessage() {
		console.log( 'This refers to: ', this );
		console.log( 'The message is: ', this.state.message );
	}

	render(){
		return( <button onClick={()=>{this.showMessage()}}>Show message from state!</button> );
	}
}
export default MyComponent;

Quelle que soit la méthode choisie, lorsque vous cliquez sur le bouton, la console du navigateur affiche le résultat suivant :

This refers to:  MyComponent {props: {…}, context: {…}, refs: {…}, updater: {…}, state: {…}, …}
The message is:  Hello World!

Opérateur ternaire

L’opérateur conditionnel (ou opérateur ternaire) vous permet d’écrire des expressions conditionnelles simples en JavaScript. Il prend trois opérandes :

  • une condition suivie d’un point d’interrogation (?),
  • une expression à exécuter si la condition est vraie, suivie de deux points (:),
  • une seconde expression à exécuter si la condition est fausse.
const drink = personAge >= 18 ? "Wine" : "Juice";

Il est également possible d’enchaîner plusieurs expressions :

const drink = personAge >= 18 ? "Wine" : personAge >= 6 ? "Juice" : "Milk";

Soyez prudent, cependant, car l’enchaînement de plusieurs expressions peut conduire à un code désordonné et difficile à maintenir.

L’opérateur ternaire est particulièrement utile dans React, notamment dans votre code JSX, qui n’accepte que les expressions entre crochets.

Par exemple, vous pouvez utiliser l’opérateur ternaire pour définir la valeur d’un attribut en fonction d’une condition spécifique :

render(){			
	const person = {
		name: 'Carlo',
		avatar: 'https://en.gravatar.com/...',
		description: 'Content Writer',
		theme: 'light'
	}

	return (
		<div
			className='card' 
			style={
				person.theme === 'dark' ? 
				{ background: 'black', color: 'white' } : 
				{ background: 'white', color: 'black'} 
			}>
			<img
				src={person.avatar}
				alt={person.name}
				style={ { width: '100%' } }
			/>
			<div style={ { padding: '2px 16px' } }>
				<h3>{person.name}</h3>
				<p>{person.description}.</p>
			</div>
		</div>
	);
}

Dans le code ci-dessus, nous vérifions la condition person.theme === 'dark' pour définir la valeur de l’attribut style du conteneur div.

Évaluation des courts-circuits

L’opérateur logique ET (&&) évalue les opérandes de gauche à droite et renvoie true si et seulement si tous les opérandes sont true.

L’opérateur logique ET est un opérateur de court-circuit. Chaque opérande est converti en booléen et, si le résultat de la conversion est false, l’opérateur ET s’arrête et renvoie la valeur originale de l’opérande faible. Si toutes les valeurs sont true, il renvoie la valeur originale du dernier opérande.



L’évaluation des courts-circuits est une fonctionnalité JavaScript couramment utilisée dans React, car elle vous permet de sortir des blocs de code en fonction de conditions spécifiques. En voici un exemple :

{
	displayExcerpt &&
	post.excerpt.rendered && (
		<p>
			<RawHTML>
				{ post.excerpt.rendered }
			</RawHTML>
		</p>
	)
}

Dans le code ci-dessus, si displayExcerpt ET post.excerpt.rendered évaluent à true, React renvoie le bloc final de JSX.

Pour résumer, « si la condition est true, l’élément situé juste après && apparaîtra dans la sortie. S’il s’agit de false, React l’ignorera et le sautera ».

Syntaxe spread

En JavaScript, la syntaxe spread vous permet d’étendre un élément itérable, tel qu’un tableau ou un objet, en arguments de fonction, en littéraux de tableau ou en littéraux d’objet.

Dans l’exemple suivant, nous décompressons un tableau dans un appel de fonction :

function doSomething( x, y, z ){
	return `First: ${x} - Second: ${y} - Third: ${z} - Sum: ${x+y+z}`;
}
const numbers = [3, 4, 7];
console.log( doSomething( ...numbers ) );

Vous pouvez utiliser la syntaxe spread pour dupliquer un tableau (même multidimensionnel) ou pour concaténer des tableaux. Dans les exemples suivants, nous concaténons deux tableaux de deux manières différentes :

const firstArray = [1, 2, 3];
const secondArray = [4, 5, 6];
firstArray.push( ...secondArray );
console.log( firstArray );

Alternativement :

let firstArray = [1, 2, 3];
const secondArray = [4, 5, 6];
firstArray = [ ...firstArray, ...secondArray];
console.log( firstArray );

Vous pouvez également utiliser la syntaxe de propagation pour cloner ou fusionner deux objets :

const firstObj = { id: '1', title: 'JS is awesome' };
const secondObj = { cat: 'React', description: 'React is easy' };

// clone object
const thirdObj = { ...firstObj };

// merge objects
const fourthObj = { ...firstObj, ...secondObj }

console.log( { ...thirdObj } );
console.log( { ...fourthObj } );

Affectation de déstructuration

Une autre structure syntaxique que vous trouverez souvent utilisée dans React est la syntaxe d’affectation de déstructuration.

Dans l’exemple suivant, nous décompressons les valeurs d’un tableau :

const user = ['Carlo', 'Content writer', 'Kinsta'];
const [name, description, company] = user;
console.log( `${name} is ${description} at ${company}` );

Voici un exemple simple d’affectation de déstructuration avec un objet :

const user = {
	name: 'Carlo',
	description: 'Content writer',
	company: 'Kinsta'
}
const { name, description, company } = user;
console.log( `${name} is ${description} at ${company}` );

Mais nous pouvons faire encore plus. Dans l’exemple suivant, nous décompressons certaines propriétés d’un objet et nous attribuons les propriétés restantes à un autre objet à l’aide de la syntaxe d’étalement :

const user = {
	name: 'Carlo',
	family: 'Daniele',
	description: 'Content writer',
	company: 'Kinsta',
	power: 'swimming'
}
const { name, description, company, ...rest } = user;
console.log( rest ); // {family: 'Daniele', power: 'swimming'}

Vous pouvez également attribuer des valeurs à un tableau :

const user = [];
const object = { name: 'Carlo', company: 'Kinsta' };
( { name: user[0], company: user[1] } = object );
console.log( user ); // (2) ['Carlo', 'Kinsta']

Notez que les parenthèses entourant l’instruction d’affectation sont nécessaires lorsque vous utilisez l’affectation de déstructuration littérale d’objet sans déclaration.

Pour une analyse plus approfondie de l’affectation de déstructuration, avec plusieurs exemples d’utilisation, veuillez vous référer à la documentation web de mdn.

filter(), map() et reduce()

JavaScript fournit plusieurs méthodes utiles que vous trouverez souvent utilisées dans React.

filter()

Dans l’exemple suivant, nous appliquons le filtre au tableau numbers pour obtenir un tableau dont les éléments sont des nombres supérieurs à 5 :

const numbers = [2, 6, 8, 2, 5, 9, 23];
const result = numbers.filter( number => number > 5);
console.log(result); // (4) [6, 8, 9, 23]

Dans l’exemple suivant, nous obtenons un tableau d’articles dont le titre contient le mot « JavaScript » :

const posts = [
	{id: 0, title: 'JavaScript is awesome', content: 'your content'},
	{id: 1, title: 'WordPress is easy', content: 'your content'},
	{id: 2, title: 'React is cool', content: 'your content'},
	{id: 3, title: 'With JavaScript to the moon', content: 'your content'},
];

const jsPosts = posts.filter( post => post.title.includes( 'JavaScript' ) );

console.log( jsPosts );
Un tableau d'articles dont le titre contient le mot
Un tableau d’articles dont le titre contient le mot « JavaScript »

map()

const numbers = [2, 6, 8, 2, 5, 9, 23];
const result = numbers.map( number => number * 5 );
console.log(result); // (7) [10, 30, 40, 10, 25, 45, 115]

Dans un composant React, vous trouverez souvent la méthode map() utilisée pour construire des listes. Dans l’exemple suivant, nous mappons l’objet WordPress posts pour construire une liste d’articles:

<ul>
	{ posts && posts.map( ( post ) => {
		return (
			<li key={ post.id }>
				<h5>
					<a href={ post.link }>
						{ 
							post.title.rendered ? 
							post.title.rendered :
							__( 'Default title', 'author-plugin' )
						}
					</a>
				</h5>
			</li>
		)
	})}
</ul>

reduce()

reduce() accepte deux paramètres :

  • Une fonction de rappel à exécuter pour chaque élément du tableau. Elle renvoie une valeur qui devient la valeur du paramètre accumulateur lors de l’appel suivant. Lors du dernier appel, la fonction renvoie la valeur qui sera la valeur de retour de reduce().
  • Une valeur initiale qui est la première valeur de l’accumulateur passée à la fonction de rappel.

La fonction de rappel prend quelques paramètres :

  • Un accumulateur: La valeur renvoyée lors de l’appel précédent à la fonction callback. Lors du premier appel, il est mis à une valeur initiale si elle est spécifiée. Sinon, elle prend la valeur du premier élément du tableau.
  • La valeur de l’élément courant: La valeur est fixée au premier élément du tableau (array[0]) si une valeur initiale a été fixée, sinon elle prend la valeur du deuxième élément (array[1]).
  • L’indice courant est la position de l’indice de l’élément courant.

Un exemple vous permettra d’y voir plus clair.

const numbers = [1, 2, 3, 4, 5];
const initialValue = 0;
const sumElements = numbers.reduce(
	( accumulator, currentValue ) => accumulator + currentValue,
	initialValue
);
console.log( numbers ); // (5) [1, 2, 3, 4, 5]
console.log( sumElements ); // 15

Voyons en détail ce qui se passe à chaque itération. Reprenez l’exemple précédent et changez le initialValue:

const numbers = [1, 2, 3, 4, 5];
const initialValue = 5;
const sumElements = numbers.reduce(
	( accumulator, currentValue, index ) => {
		console.log('Accumulator: ' + accumulator + ' - currentValue: ' + currentValue + ' - index: ' + index);
		return accumulator + currentValue;
	},
	initialValue
);
console.log( sumElements );

L’image suivante montre la sortie dans la console du navigateur :

En utilisant reduce() avec une valeur initiale fixée à 5
En utilisant reduce() avec une valeur initiale fixée à 5

Voyons maintenant ce qui se passe sans le paramètre initialValue:

const numbers = [1, 2, 3, 4, 5];
const sumElements = numbers.reduce(
	( accumulator, currentValue, index ) => {
		console.log( 'Accumulator: ' + accumulator + ' - currentValue: ' + currentValue + ' - index: ' + index );
		return accumulator + currentValue;
	}
);
console.log( sumElements );
Utilisation de reduce() sans valeur initiale
Utilisation de reduce() sans valeur initiale

D’autres exemples et cas d’utilisation sont présentés sur le site web mdn web docs.

Exportations et importations

Depuis ECMAScript 2015 (ES6), il est possible d’exporter des valeurs d’un module JavaScript et de les importer dans un autre script. Vous utiliserez largement les imports et les exports dans vos applications React et il est donc important de bien comprendre leur fonctionnement.

Le code suivant crée un composant fonctionnel. La première ligne importe la bibliothèque React :

import React from 'react';

function MyComponent() {
	const person = {
		name: 'Carlo',
		avatar: 'https://en.gravatar.com/userimage/954861/fc68a728946aac04f8531c3a8742ac22?size=original',
		description: 'Content Writer',
		theme: 'dark'
	}
 
	return (
		<div
			className = 'card'
			style = {
				person.theme === 'dark' ?
				{ background: 'black', color: 'white' } :
				{ background: 'white', color: 'black'}
			}>
			<img
				src = { person.avatar }
				alt = { person.name }
				style = { { width: '100%' } }
			/>
			<div
				style = { { padding: '2px 16px' } }
			>
				<h3>{ person.name }</h3>
				<p>{ person.description }.</p>
			</div>
		</div>
	);
}
export default MyComponent;

Nous avons utilisé le mot-clé import suivi du nom que nous voulons attribuer à ce que nous importons, suivi du nom du package que nous voulons installer tel qu’il est référencé dans le fichier package.json.

Notez que dans la fonction MyComponent() ci-dessus, nous avons utilisé certaines des fonctionnalités JavaScript abordées dans les sections précédentes. Nous avons inclus les valeurs des propriétés entre crochets et attribué la valeur de la propriété style à l’aide de la syntaxe de l’opérateur conditionnel.

Le script se termine par l’exportation de notre composant personnalisé.

Maintenant que nous en savons un peu plus sur les importations et les exportations, examinons de plus près leur fonctionnement.

Export

Chaque module React peut avoir deux types d’exportation différents: l’exportation nommée et l’exportation par défaut.

Par exemple, vous pouvez exporter plusieurs fonctionnalités à la fois avec une seule déclaration export:

export { MyComponent, MyVariable };

Vous pouvez également exporter des fonctionnalités individuelles (function, class, const, let) :

export function MyComponent() { ... };
export let myVariable = x + y;

Mais vous ne pouvez avoir qu’une seule exportation par défaut :

export default MyComponent;

Vous pouvez également utiliser l’exportation par défaut pour des caractéristiques individuelles :

export default function() { ... }
export default class { ... }

Import

Une fois le composant exporté, il peut être importé dans un autre fichier, par exemple un fichier index.js, avec d’autres modules :

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import MyComponent from './MyComponent';

const root = ReactDOM.createRoot( document.getElementById( 'root' ) );
root.render(
	<React.StrictMode>
		<MyComponent />
	</React.StrictMode>
);

Dans le code ci-dessus, nous avons utilisé la déclaration import de plusieurs façons.

Dans les deux premières lignes, nous avons attribué un nom aux ressources importées, dans la troisième ligne, nous n’avons pas attribué de nom mais simplement importé le fichier ./index.css. La dernière déclaration import importe le fichier ./MyComponent et lui attribue un nom.

Découvrons les différences entre ces importations.

Au total, il existe quatre types d’importations :

Importation nommée

import { MyFunction, MyVariable } from "./my-module";

Importation par défaut

import MyComponent from "./MyComponent";

Importation d’un espace de noms

import * as name from "my-module";

Importation d’effets secondaires

import "module-name";

Une fois que vous avez ajouté quelques styles dans votre index.css, votre carte devrait ressembler à l’image ci-dessous, où vous pouvez également voir le code HTML correspondant :

Un simple composant React
Un simple composant React

Notez que les déclarations import ne peuvent être utilisées que dans les modules au niveau supérieur (pas à l’intérieur des fonctions, des classes, etc.).

Pour un aperçu plus complet des déclarations import et export, vous pouvez également consulter les ressources suivantes :

Résumé

React est l’une des bibliothèques JavaScript les plus populaires aujourd’hui et l’une des compétences les plus demandées dans le monde du développement web.

Avec React, il est possible de créer des applications web dynamiques et des interfaces avancées. Créer de grandes applications dynamiques et interactives peut être facile grâce à ses composants réutilisables.

Mais React est une bibliothèque JavaScript, et une bonne compréhension des principales fonctionnalités de JavaScript est essentielle pour commencer votre voyage avec React. C’est pourquoi nous avons rassemblé en un seul endroit certaines des fonctionnalités JavaScript que vous trouverez le plus souvent utilisées dans React. Maîtriser ces fonctionnalités vous donnera une longueur d’avance sur votre parcours d’apprentissage de React.

Et lorsqu’il s’agit de développement web, passer de JS/React à WordPress ne demande que très peu d’efforts.

Maintenant, c’est à vous de jouer, quelles sont les fonctionnalités JavaScript qui vous semblent les plus utiles dans le développement React ? Avons-nous oublié quelque chose d’important que vous auriez aimé voir sur notre liste ? Faites-nous part de vos réflexions dans les commentaires ci-dessous.

Carlo Daniele Kinsta

Carlo est un passionné de webdesign et de développement frontend. Il joue avec WordPress depuis plus de 10 ans, notamment en collaboration avec des universités et des établissements d'enseignement italiens et européens. Il a écrit des dizaines d'articles et de guides sur WordPress, publiés à la fois sur des sites web italiens et internationaux, ainsi que dans des magazines imprimés. Vous pouvez trouver Carlo sur X et LinkedIn.