Vous êtes sur la page 1sur 28

PROSIT

Sommaire
Contexte :...............................................................................................................................................3
Problématique :.....................................................................................................................................3
Plan d’action :........................................................................................................................................3
I. Définition.......................................................................................................................................3

2
Dario VECCHIO
PROSIT

Contexte :
On veut ajouter des applications en Node JS sur notre site. (Pierre)
on cherche à trouver une solution pour ne pas agir en mode synchronisé, mais en mode
asynchronisé. (Tristan)
Après avoir observé des sites de e-commerce tomber durant la période du black Friday, on
cherche à trouver une solution pour ne pas agir en mode synchronisé.

Problématique :
- Comment mettre en place un site tournant sur Node JS ?

Contraintes :
- Notre site

- Node JS

- MVC (seulement pour Thibault)

Besoins :
- connaitre le fonctionnement d’un serveur classique

- comment implémenter Node JS

- comprendre et utiliser React

Plan d’action :
- Mode synchronisé / asynchronisé
- Node JS
o L’environnement
 Comment l’installer ?
o Comment les relier entre nos différents éléments
o Comment faire un serveur http en Node JS
- React

Réalisation :

- Mettre en place le serveur Node JS


- Faire des interactions entre le client et le serveur (diagramme de séquences)
- Prise en main du framework

3
Dario VECCHIO
PROSIT

I. Définition

- Mode synchronisé

- Evènement

- .jsx (extension)

- Client/serveur

- Node JS

- Framework

- Elément bloquant

- trafic

II. Mode Synchronisé et Asynchronisé


En JavaScript, beaucoup d’opérations ont un fonctionnement dit "asynchrone", c’est-à-dire un
fonctionnement non bloquant qui va nous permettre de lancer une tâche et d’avancer dans le
programme le temps que cette tâche s’exécute (ex : lorsque l’on manipule des éléments HTML ou
que l’on fait des requêtes AJAX, la page n’est pas bloquée).
Voici un exemple :
console.log("Premier")

setTimeout(function () {
console.log("Deuxième")
}, 1000);

console.log("Troisième")

// ==> Résultat:
// Premier
// Troisième
// Deuxième
La fonction "setTimeout" prend deux paramètres : une fonction (appelée callback) et un entier
qui est le nombre de millisecondes à attendre avant d’appeler le callback. Étant donné que
"setTimeout" est asynchrone, le script va continuer son déroulement jusqu’à ce que le callback
soit appelé.

4
Dario VECCHIO
PROSIT

Les callbacks
Un callback est une fonction de rappel passée en paramètre d’une autre fonction et qui sera
appelée à la fin de cette dernière pour effectuer une autre opération . Plus clairement, utiliser un
callback se résume à dire "j’exécute la fonction B une fois que la fonction A est terminée".
Un petit exemple pour illustrer ce procédé :
function helloWorld() {
console.log("Hello World !");
}

function setup(soft, callBack) {


console.log("Installation de " + soft);
callBack()
}

setup("Nginx", helloWorld)

// ==> Résultat:
// Installation de Nginx
// Hello World !
Ici la fonction "helloWorld" est passée en paramètre de la fonction "setup", c’est bien un
callback. Les callbacks sont beaucoup utilisés pour faire des requêtes HTTP, pour traiter des
fichiers (avec NodeJS) ou encore dans la déclaration des événements, comme le montre cet
exemple :
document.getElementById("monBouton").addEventListener("click", function() {
alert("Vous avez cliqué sur le bouton !")
});
Depuis la 6e version du standard EcmaScript (2015), une nouvelle syntaxe a été mise à
disposition pour définir une fonction, elle s’appelle la fonction fléchée.
Elle se construit sous cette forme :
myFunction = () => {
console.log("Fonction fléchée !")
}
Les fonctions fléchées sont principalement utilisées comme des callbacks.
Si l’on reprend l’exemple précédent avec cette syntaxe plus simpliste, cela nous donne :
document.getElementById("monBouton").addEventListener("click", () => {
alert("Vous avez cliqué sur le bouton !")
});
Les Promises
L’objet "Promise" permet de faire des opérations asynchrones plus simplement . Son
fonctionnement est simple : on lance une opération de manière asynchrone dont on attend un
résultat dans le futur (promesse, comme son nom l’indique).
Elle se construit de cette manière :
new Promise(function(resolve, reject) {

5
Dario VECCHIO
PROSIT

setTimeout(function () {
resolve("Promise résolue")
}, 1000);
});
La Promise prend en paramètre une fonction qu’elle exécute immédiatement et qui prend elle
même deux paramètres : une fonction de callback qui permet de signaler que la promesse a été
tenue (tout s’est bien passé donc on retourne le résultat) et une deuxième fonction de callback
qui permet cette fois de signaler que la promesse est en échec (possibilité de retourner une
erreur).
Un avantage de la Promise est qu’elle peut être dans 3 états différents :
 Pending (en attente): l’opération est en cours d’exécution.
 Fulfilled (satisfaite) : l’opération est terminée et a réussie.
 Rejected (rejetée) : l’opération est terminée et a échouée.
On peut donc effectuer une tâche asynchrone, attendre la fin de celle-ci sans bloquer le fil
d’exécution du processus puis continuer le déroulement de notre script.
Voici un exemple montrant comment traiter la donnée d’une requête HTTP
function getHTTP(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = function() {
if (this.status >= 200 && this.status < 300) {
resolve(xhr.response);
}
};
xhr.open("GET", url);
xhr.send();
});
}

getHTTP("https://www.google.fr")
.then(function (response) {
// On récupère le resultat de la requête dans la varible "response"
console.log(response)
})
La fonction "getHTTP" va retourner une Promise qui elle-même va retourner le résultat de la
requête HTTP, il nous suffi t de chaîner la fonction avec ".then()" pour récupérer le résultat . Cette
fonction nous permet de réduire le nombre de lignes et de simplifier la façon de faire des
requêtes asynchrones (ici dans un navigateur Web avec l’objet "XMLHttpRequest").
Vous l’aurez peut-être remarqué, si la requête ne fonctionne pas, la Promise ne se terminera
jamais car nous ne prenons pas en charge les erreurs.

6
Dario VECCHIO
PROSIT

Pour gérer les erreurs, la façon la plus simple est d’utiliser la méthode "catch" de l’objet
Promise. Comme "then", elle prend en paramètre un callback qui sera retourné par la Promise, à
la différence près qu’elle prendra uniquement le callback que va rejeter la Promise (si il y a une
erreur).
Voici le code précédent, adapté pour prendre en compte les erreurs :
function getHTTP(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = function() {
if (this.status >= 200 && this.status < 300) {
resolve(xhr.response);
}
else {
reject({
status: this.status,
statusText: this.statusText
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: this.statusText
});
};
xhr.open("GET", url);
xhr.send();
});
}

getHTTP("https://www.google.fr")
.then(function (response) {
// On récupère le resultat de la requête dans la varible "response"
console.log(response)
})
.catch(function (error) {
// On affiche le code de retour de la requête
console.log(error.status)
// Puis le texte du status
console.log(error.statusText)
})

7
Dario VECCHIO
PROSIT

Un problème qui arrive assez souvent en JavaScript, est le fait d’écrire des fonctions imbriquées
les unes dans les autres, plus communément appelé le "callback hell".
Exemple :
getHTTP("https://www.google.fr")
.then(function (googleResponse) {
getHTTP("https://www.supinfo.com")
.then(function (supResponse) {
getHTTP("https://example.com")
.then(function (exampleResponse) {
console("End of callBack hell !")
})
.catch(function (thirdError) {
console.log(thirdError.status)
}) })
.catch(function (secondError) {
console.log(secondError.status)
})})
.catch(function (firstError) {
console.log(firstError.status)
})
Ce bout de code fait 3 requêtes les unes après les autres en prenant en compte les erreurs pour
chaque requête. Comme vous pouvez le remarquer ce n’est pas très lisible (voir pas du tout),
alors pour palier à ce problème deux solutions s’offrent à nous :
 Exécuter toutes les requêtes en même temps
 Chaîner les Promises
Pour la première solution nous avons besoin de la méthode "Promise.all()", qui prend en
paramètre un tableau de Promise et qui retournera une unique Promise, une fois que la liste de
Promises sera traitée :
Promise.all([getHTTP("https://www.google.fr"), getHTTP("https://www.supinfo.com"),
getHTTP("https://example.com")])
.then(function (data) {
var googleResponse = data[0];
var supResponse = data[1];
var exampleResponse = data[2];
})
.catch(function (error) {
console.log(error.status)
})
Cette solution est la plus courte (en termes de ligne) mais elle ne peut pas être utilisée dans le
cas où l’on veut faire les appels un à un pour utiliser la valeur de la précédente requête avant de
faire la suivante. Cela tombe bien, la seconde solution est là pour ça :
getHTTP("https://www.google.fr")
.then(function (googleResponse) {
console.log(googleResponse);

8
Dario VECCHIO
PROSIT

return getHTTP("https://www.supinfo.com")
})
.then(function (supResponse) {
console.log(supResponse);
return getHTTP("https://example.com")
})
.then(function (exampleResponse) {
console.log("end");
})
.catch(function (error) {
console.log(error.status)
})
Ici les Promises sont chaînées. Lors du retour de la première Promise nous pouvons alors faire un
traitement spécifique sur le résultat, on retourne une autre Promise puis une fois celle-ci résolue
on passe à la méthode "then" suivante et ainsi de suite.
Dans les deux exemples précédents, la méthode "catch" n’était présente qu’une seule fois, elle
permet d’intercepter toutes les erreurs des précédentes Promises et également de garantir une
syntaxe simple et plus compréhensible (on économise également quelques lignes de code).
Il est également possible d’ajouter un ".then()" supplémentaire à la fin du script qui permet
d’exécuter une fonction dans tous les cas, peu importe le résultat des Promise précédentes :
getHTTP("https://www.google.fr")
.then(function (googleResponse) {
return getHTTP("pageInexistan.te")
})
.then(function (res) {
console.log(res);
})
.catch(function (error) {
console.log(error.status)
})
.then(function () {
console.log("Opérations terminées");
})
Async / Await
"Async" et "Await" sont deux opérateurs issus de l’EcmaScript 7 (2016), s’inspirant d’autres
langages comme le Python ou le C#, qui ont beaucoup réjoui les développeurs JavaScript à leur
arrivé. Avant que ces opérateurs soient standardisés, nous étions obligé d’utiliser de multitudes
de callbacks qui rendaient souvent le code peu lisible. Maintenant, nous pouvons faire des
appels à des fonctions asynchrone en utilisant la syntaxe d’un code synchrone, ce qui rend
visuellement plus logique et plus simple à comprendre.
Voici un exemple pour illustrer cet avantage :
async function main() {
var googleResponse = await getHTTP("https://www.google.fr")
console.log(googleResponse);

9
Dario VECCHIO
PROSIT

var supResponse = await getHTTP("https://www.supinfo.com")


console.log(supResponse);
}

main()
Comme on peut le voir, il n’y a aucun callback, et le code se lit très facilement.
Le fonctionnement technique de ces opérateurs est assez simple :
 On place "async" en premier lieu lorsque l’on déclare une fonction pour préciser que
celle-ci est asynchrone.
 On place "await" juste avant d’appeler une fonction asynchrone, ce qui aura pour but
d’attendre la réponse de cette dernière.
Tout ça n’est pas magique. En réalité, Async va automatiquement transformer la fonction en une
Promise et va résoudre celle-ci avec le résultat retourner par "return". Grâce à Async, on a accès
à Await dans la fonction, qui lui permet de forcer le reste du code à attendre que la Promise soit
résolue et qu’elle retourne un résultat (ou une erreur).
Await fonctionne seulement dans une fonction précédée de Async et permet d’attendre
uniquement une Promise.
Exemple avec un callback :
async function sleep() {
await setTimeout(function () {
return "wake up !"
}, 1000);
}

sleep().then(function(res) {
console.log(res);
})
Le code ci-dessus n’affi chera rien à l’écran. Comme Await n’attend pas les callbacks, la fonction
"sleep" va se terminer directement sans rien retourner.
Pour obtenir une fonction "sleep" comme celle présente en Bash, nous pourrions faire comme
cela :
function sleep(time){
return new Promise(function(resolve) {
setTimeout(function () {
resolve()
}, time);
})
}
async function main() {
console.log("Sleeping..");
await sleep(1000)
return "wake up !"
}

10
Dario VECCHIO
PROSIT

main().then(function(res) {
console.log(res);
})
Async et Await ne remplacent pas les Promises, ils permettent uniquement de simplifier l’appel
de celles-ci.
La bonne pratique lorsque l’on utilise ces opérateurs, est de découper toutes les tâches
asynchrones en différentes fonctions qui retournent une Promise. Ensuite, il ne reste plus qu’à
appeler ces fonctions avec Await dans la partie principale du code, et adieu les callbacks !
Pour prendre en charge les erreurs des fonctions utilisant Async/Await, on utilise simplement le
bon vieux "try/catch" :
function errorFunction(){
return new Promise(function(resolve, reject) {
setTimeout(function () {
reject("There is a bug !")
}, 1000);
})
}

async function main() {


try {
await errorFunction()
} catch (error) {
console.log(error);
}
}

main()
Dans le cas si dessus, nous pourrions également prendre en compte les erreurs lorsque l’on
appelle la fonction "main" en chaînant avec la méthode "catch" :
async function main() {
await errorFunction()
}

main()
.then(function () {
console.log("done");
})
.catch(function (error) {
console.log(error)
})
Il est possible d’exécuter une liste de Promises et d’attendre le retour de celles-ci avant de
continuer le déroulement du script, alors comment adapter ce procédé avec les opérateurs
Async/Await ?

11
Dario VECCHIO
PROSIT

exemple :
async function main() {
var [googleResponse, supResponse] = await
Promise.all([getHTTP("https://www.google.fr"), getHTTP("https://www.supinfo.com")])
console.log(googleResponse);
console.log(supResponse);
}

main()
On précède simplement la méthode "Promise.all()" (qui retournera un tableau de résultats) avec
"await".

Conclusion
Il est important de se rappeler que les opérateurs Async/Await utilisent les Promises, ne les
remplacent pas et permettent simplement de faciliter l’écriture et la compréhension du code.

Avant de commencer le développement d’un nouveau site Web qui utilise les Promises, il est
conseillé de vérifier si la version des navigateurs ciblés est compatible (il en est de même pour
NodeJS).

Il est ainsi possible de dire que JavaScript est un peu plus qu'un langage, c'est aussi une architecture.

12
Dario VECCHIO
PROSIT

III. Node Js

Crée son premier serveur Node. Js

Créez un fichier nommé "app.js" et collez le code suivant:

const http = require('http');

const hostname = '127.0.0.1';

const port = 3000;

Node.js nous permet d'utiliser le langage JavaScript sur le serveur... Il nous permet donc
de faire du JavaScript en dehors du navigateur !
Node.js bénéficie de la puissance de JavaScript pour proposer une toute nouvelle façon de
développer des sites web dynamiques. Node.js nous permet d'utiliser le langage JavaScript
sur le serveur... Il nous permet donc de faire du JavaScript en dehors du navigateur !

13
Dario VECCHIO
PROSIT

Node.js bénéficie de la puissance de JavaScript pour proposer une toute nouvelle façon de
développer des sites web dynamiques.

Node.js nous permet d'utiliser le langage JavaScript sur le serveur... Il nous permet donc de faire du
JavaScript en dehors du navigateur !

Node.js bénéficie de la puissance de JavaScript pour proposer une toute nouvelle façon de
développer des sites web dynamiques.

Node.js offre un environnement côté serveur qui nous permet aussi d'utiliser le langage JavaScript
pour générer des pages web. En gros, il vient en remplacement de langages serveur comme PHP,
Java EE, etc.

Avec Node.js, vous pouvez créer des applications rapides comme :

 Un serveur de Chat

 Un système d'upload très rapide

 ... et de façon générale n'importe quelle application qui doit répondre à de nombreuses
requêtes rapidement et efficacement, en temps réel

Le modèle non bloquant


Comme JavaScript est un langage conçu autour de la notion d'évènement, Node.js a pu mettre en
place une architecture de code entièrement non bloquante.

Mais au fait, connaissez-vous la différence entre un code bloquant et un code non bloquant ?
Hmmm, un peu d'explications ne peuvent pas faire de mal je vois ! 

Modèle bloquant vs modèle non bloquant


Imaginez un programme dont le rôle est de télécharger un fichier puis de l'afficher. Voici comment
on écrirait le code dans un modèle bloquant :

Télécharger un fichier

Afficher le fichier

Faire autre chose

14
Dario VECCHIO
PROSIT

Les actions sont effectuées dans l'ordre. Il faut lire les lignes de haut en bas :

1. Le programme va télécharger un fichier sur Internet


2. Le programme affiche le fichier à l'utilisateur
3. Puis ensuite le programme peut faire d'autres choses (effectuer d'autres actions)
Maintenant, on peut écrire le même code sur un modèle non bloquant :

Télécharger un fichier

Dès que c'est terminé, afficher le fichier

Faire autre chose


Le programme n'exécute plus les lignes dans l'ordre où elles sont écrites. Il fait ceci :

1. Le programme lance le téléchargement d'un fichier sur Internet

2. Le programme fait d'autres choses (le programme suit son cours)

3. Dès que le téléchargement est terminé, le programme effectue les actions qu'on lui avait
demandées : il affiche le fichier

Le modèle non bloquant avec Node.js


Bon, et avec du vrai code ça donne quoi ? Voici un exemple de programme Node.js qui télécharge un
fichier sur Internet et affiche "Fichier téléchargé !" quand il a terminé :

request('http://www.site.com/fichier.zip', function (error, response, body) {

console.log("Fichier téléchargé !");

});

console.log("Je fais d'autres choses en attendant...");


La requête de téléchargement est lancée en premier. Ensuite, le programme fait d'autres choses (ici,
il affiche un message dans la console, mais il pourrait faire n'importe quoi d'autre). Dès que le
téléchargement est terminé, le programme va à la ligne 2 et affiche "Fichier téléchargé !".

Ceci est une fonction de callback.

On dit que c'est une fonction anonyme. Mais on pourrait décomposer ce code comme
ceci, le résultat serait identique :

// Résultat identique au code précédent

var callback = function (error, response, body) {

console.log("Fichier téléchargé !");

15
Dario VECCHIO
PROSIT

});

request('http://www.site.com/fichier.zip', callback);

console.log("Je fais d'autres choses en attendant...");


La fonction de callback est enregistrée dans une variable. Comme toutes les fonctions, elle
n'est pas exécutée tant qu'on ne l'a pas appelée.
Ensuite, on envoie cette fonction de callback en paramètre de la fonction request() pour dire
: "Dès que la requête de téléchargement est terminée, appelle cette fonction de callback".

En pratique, les développeurs JavaScript mettent régulièrement des fonctions anonymes


directement à l'intérieur d'autres fonctions en paramètre, comme dans mon premier code

Node.js est monothread, contrairement à Apache. Cela veut dire qu'il n'y a qu'un seul processus,
qu'une seule version du programme qui peut tourner à la fois en mémoire.

Malgré ça il est quand même beaucoup plus rapide !

Cela est dû à la nature "orientée évènements" de Node.js. Les applications utilisant Node ne restent
jamais les bras croisés sans rien faire. Dès qu'il y a une action un peu longue, le programme redonne
la main à Node.js qui va effectuer d'autres actions en attendant qu'un évènement survienne pour
dire que l'opération est terminée.

16
Dario VECCHIO
PROSIT

Construire son serveur http

var http = require('http');

var server = http.createServer(function(req, res) {

res.writeHead(200);

res.end('Salut tout le monde !');

});

server.listen(8080);
C'est en quelque sorte le "code minimal" pour un projet Node.js. Placez-le dans un fichier
que vous appellerez serveur.js (par exemple).

17
Dario VECCHIO
PROSIT

Tout le code ci-dessus correspond à l'appel à createServer(). Il comprend en paramètre la


fonction à exécuter quand un visiteur se connecte à notre site.

Notez que vous pouvez faire ça en deux temps comme je vous l'avait dit. La fonction à
exécuter est la fonction de callback. On peut la définir avant dans une variable et
transmettre cette variable à createServer(). Ainsi, le code ci-dessous est strictement
identique au précédent :

// Code identique au précédent

var instructionsNouveauVisiteur = function(req, res) {

res.writeHead(200);

res.end('Salut tout le monde !');

var server = http.createServer(instructionsNouveauVisiteur);

Il y a des fonctions de callback de partout, et en général elles sont placées à l'intérieur des arguments
d'une autre fonction.

fermer la fonction de callback avec une accolade, puis de fermer les parenthèses d'appel de la
fonction qui l'englobe, puis de placer le fameux point-virgule. C'est pour ça que vous voyez les
symboles});à la dernière ligne

La fonction de callback est donc appelée à chaque fois qu'un visiteur se connecte à notre site. Elle
prend 2 paramètres :

 La requête du visiteur (reqdans mes exemples) : cet objet contient toutes les informations
sur ce que le visiteur a demandé. On y trouve le nom de la page appelée, les paramètres, les
éventuels champs de formulaires remplis...

 La réponse que vous devez renvoyer (resdans mes exemples) : c'est cet objet qu'il faut
remplir pour donner un retour au visiteur. Au final, res contiendra en général le code HTML
de la page à renvoyer au visiteur.

Comment faire pour renvoyer du HTML.


il y a des règles à respecter entre le client et le serveur. Ils communiquent en se basant sur la norme
HTTP inventée par Tim Berners-Lee. Cette norme est à la base du Web (tout comme le langage HTML
qui a aussi été inventé par ce même monsieur   ).

Que dit la norme HTTP ? Que le serveur doive indiquer le type de données qu'il s'apprête à envoyer
au client. Eh oui, un serveur peut renvoyer différents types de données :

18
Dario VECCHIO
PROSIT

 Du texte brut : text/plain

 Du HTML : text/html

 Du CSS : text/css

 Une image JPEG : image/jpeg

 Une vidéo MPEG4 : video/mp4

 Un fichier ZIP : application/zip

 etc.

Ce sont ce qu'on appelle les types MIME.

On doit indiquer à la suite de la réponse du serveur Node.js le type MIME de la réponse. Pour
HTML, ce sera donc :

res.writeHead(200, {"Content-Type": "text/html"});

Pour récupérer la page demandée par le visiteur, on va faire appel à un nouveau module de
Node appelé "url". On demande son inclusion avec :

var url = require("url");


Ensuite, il nous suffit de "parser" la requête du visiteur comme ceci pour obtenir le nom de
la page demandée :

url.parse(req.url).pathname;
Voici un code très simple qui nous permet de tester ça :

var http = require('http');

var url = require('url');

var server = http.createServer(function(req, res) {

var page = url.parse(req.url).pathname;

console.log(page);

res.writeHead(200, {"Content-Type": "text/plain"});

res.write('Bien le bonjour');

res.end();

});

19
Dario VECCHIO
PROSIT

server.listen(8080);

Le problème, c'est qu'on vous renvoie toute la chaîne sans découper au préalable les
différents paramètres. Heureusement, il existe un module Node.js qui s'en charge pour
nous : querystring !

Incluez ce module :

var querystring = require('querystring');


Vous pourrez ensuite faire :

var params = querystring.parse(url.parse(req.url).query);


Vous disposerez alors d'un tableau de paramètres "params". Pour récupérer le paramètre
"prenom" par exemple, il suffira d'écrire :params['prenom'].

IV. React.js

React n’est pas à proprement parler un framework mais se présente comme une bibliothèque
JavaScript pour créer des interfaces utilisateurs. React est la réponse de Facebook à un problème
récurrent : créer des interfaces réutilisables et stateful.

React est basé sur virtual-dom : un composant React ne crée pas de HTML mais une représentation
sous forme d’objets et de nœuds de ce à quoi le HTML final doit ressembler. Virtual-dom va prendre
en compte cette représentation, la comparer au DOM réel et en déduire les opérations minimales à
exécuter pour que le DOM réel soit conforme au virtuel. C’est grâce à cet outil que React peut partir
du principe qu’il est plus simple de “remplacer” toute l’interface quand elle doit être modifiée plutôt
que de modifier au fur et à mesure le DOM comme jQuery ou AngularJS pouvaient le faire.

L’intérêt de cette approche est assez simple. On reproche souvent à JavaScript d’être lent alors que
c’est DOM qui l’est. Avoir une représentation sous forme d’arbre en JavaScript permet de réaliser
beaucoup plus d’opérations, d’utiliser les meilleurs algorithmes de comparaison d’arbres et, cerise
sur le gâteau, de faire toutes les modifications du DOM en une opération plutôt qu’au fur et à
mesure. Virtual-dom est également bien plus facile à mettre à jour et à améliorer que les différentes
implémentations de DOM dans les navigateurs.

Prenons un exemple pour expliquer tout ça. Voici le « hello world » de React (en ES2015)

import React from "react";

20
Dario VECCHIO
PROSIT

import ReactDOM from "react-dom";

const Hello = React.createClass({

render() {

return React.createElement('div', null, "hello world")

});

ReactDOM.render(React.createElement(Hello), document.getElementById("app"));

L’appel  ReactDOM.render  va exécuter la fonction  render  et récupérer un arbre DOM virtuel, le
comparer à l’arbre DOM contenu dans l’élément qui a pour identifiant  app  et y ajouter le
texte “hello world”.  React.createElement  prend en paramètre l’élément HTML, un objet
d’attributs et des enfants (tous les paramètres après le 2ème seront des enfants). Rien
d’extraordinaire pour le moment mais ajoutons un peu d’interactivité (et oublions
les  import  par simplicité).

const Hello = React.createClass({

getInitialState() {

return {

hello: "world"

};

},

21
Dario VECCHIO
PROSIT

handleInputChange(e) {

this.setState({

hello: e.target.value

});

},

render() {

return React.createElement(

'div',

null,

React.createElement(

'input',

value: this.state.hello,

onChange: this.handleInputChange

},

null

),

React.createElement(

22
Dario VECCHIO
PROSIT

'div',

null,

"hello " + this.state.hello

);

});

ReactDOM.render(React.createElement(Hello), document.getElementById("app"));

Revenons au concept de stateful : ici, notre composant a un état (state) dont la valeur par
défaut est définie dans  getInitialState . On peut y accéder dans  render  avec  this.state  et on
l’assigne à la fois en valeur à notre input et en texte. On utilise l’attribut  onChange  (comme en
HTML) sur notre input pour lier l’évènement à une fonction du composant qui a la charge de
mettre à jour l’état par la méthode  setState  et c’est là que le virtual-dom entre en jeu.
Appeler  setState  va provoquer un rendu (render), dont la valeur de retour va être différente
du DOM actuel et les changements seront donc appliqués.

JSX
Passons à un autre élément important de React : les appels à  React.createElement  sont très vite
verbeux et pas forcément évidents à lire. La solution classique à ce problème est JSX : une
extension de la syntaxe JavaScript qui ressemble au HTML. Le même exemple ci dessus avec
JSX donne :

const Hello = React.createClass({

getInitialState() {

return {

23
Dario VECCHIO
PROSIT

hello: "world"

};

},

handleInputChange(e) {

this.setState({

hello: e.target.value

});

},

render() {

return (

<div>

<input value={this.state.hello} onChange={this.handleInputChange} />

<div>hello {this.state.hello}</div>

</div>

);

});

24
Dario VECCHIO
PROSIT

ReactDOM.render(<Hello />, document.getElementById("app"));

Il existe deux avantages à cette approche au delà de la concision : se rapprocher du résultat


final par la ressemblance au HTML et adopter une mentalité déclarative.  render est une
fonction qui doit être la plus rapide possible car elle va être invoquée très fréquemment, il
est donc important d’éviter de réaliser trop d’opérations à l’intérieur. Adopter JSX renforce
l’idée que  render  ne doit faire que déclarer la forme du rendu final.

Cependant JSX nécessite une phase de transpilation : elle peut être réalisée avec Babel,
directement avec la version 5, ou via le preset “React” pour Babel 6. Babel 6 a en effet été
totalement réécrit pour être modulaire et ne fait aucune transformation par défaut : il y a
maintenant un plugin par transformation et les presets sont un regroupement de ces
transformations. Le preset ES2015 par exemple permet les transformations qui
correspondent aux nouveautés de la dernière version de JavaScript.

Il existe d’autres façons de faire si la transpilation ou le JSX vous déplait, notamment React-


hyperscript qui simplifie l’écriture avec une fonction  h  du type  h(componentOrTag, properties,
children)  ou encore hyperscript-helper qui s’inspire de Elm pour fournir des fonctions dont les
noms sont ceux des éléments  div() ,  ul() …

Props et functional components


Il est possible d’avoir un état dans tout composant React mais il est recommandé de se
limiter le plus possible car de tels composants deviennent plus complexes et il n’est pas
possible de faire remonter les données vers un composant parent. Les propriétés (props)
sont là pour pallier ce problème. Outre les attributs HTML classiques, on peut passer
n’importe quel couple clé/valeur à un composant React. Le composant Hello pourrait être
transformé pour être réutilisable avec différentes valeurs.

const Hello = React.createClass({

render() {

return <div>hello {this.props.who}</div>;

});

25
Dario VECCHIO
PROSIT

ReactDOM.render(<Hello who="Synbioz" />, document.getElementById("app"));

De plus, depuis React 0.14 (aka React 14), il est possible de réaliser des composants sous
forme d’une simple fonction, essentiellement la fonction  render . C’est ce qu’on appelle la
plupart du temps des functional components. Cette fonction prend en paramètre l’objet
représentant les propriétés (props). En utilisant le destructuringd’ES2015, on peut donc
transformer le composant Hello de cette façon :

const Hello = function({who}) {

return <div>hello {who}</div>;

ReactDOM.render(<Hello who="Synbioz" />, document.getElementById("app"));

Et à partir de là, on peut faire remonter les interactions vers un composant de plus haut
niveau pour composer avec cet élément.

const Hello = function({who}) {

return <div>hello {who}</div>;

const App = React.createClass({

getInitialState() {

return {

26
Dario VECCHIO
PROSIT

hello: "world"

};

},

handleInputChange(e) {

this.setState({

hello: e.target.value

});

},

render() {

return (

<div>

<input value={this.state.hello} onChange={this.handleInputChange} />

<Hello who={this.state.hello} />

<Hello who={this.state.hello.split("").reverse().join("")} />

</div>

});

27
Dario VECCHIO
PROSIT

ReactDOM.render(<App />, document.getElementById("app"));

Utiliser en priorité les props est conseillé pour la réutilisabilité : sans état, un composant est
plus simple à prendre en main et son rendu est parfaitement prévisible ; donc plus simple à
tester et à débugger. Cependant, il n’est pas nécessaire de n’avoir qu’un composant qui gère
toutes les données de l’application. Un module précis (ex : un accordéon) pourrait stocker
dans son état quelques informations qui ne concernent que lui. De la même façon, il vaut
mieux n’utiliser l’état que pour des informations d’interface ou des petites données. Si vos
besoins venaient à être plus importants, il vaut mieux s’orienter vers une bibliothèque
dédiée basée sur Flux ou Redux.

Dom Virtuel
React a inauguré la notion de DOM virtuel : React lui-même ne manipule pas directement le DOM du
navigateur. Cela serait coûteux en performance et empêcherait de décliner cette approche sur
d’autres supports tels que les applications mobiles natives, les terminaux textuels, les fichiers PDF,
etc.

À la place, React nous fait décrire un DOM virtuel, absolument distinct du DOM des navigateurs. Au
moment venu il réconcilie ce DOM virtuel avec la couche de rendu réelle (par exemple, le DOM du
navigateur, ou, si on est côté serveur, la production du texte HTML à renvoyer côté client), en
prenant soin de minimiser le nombre d'opérations nécessaires.

28
Dario VECCHIO

Vous aimerez peut-être aussi