Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Présentation de React JS

Compatible 1.0. Cliquer pour en savoir plus sur les compatibilités.Par dcz (David CHOLLEZ), le 27 avril 2016

Depuis quelques années, le Javascript fait un retour en force et pas un mois ne passe sans qu’on voit sortir un nouveau framework encore plus génial, du moins à en croire la doc.

En 2013, Facebook annonce ReactJS. Depuis cette librairie a été adoptée par de grands noms comme Netflix, Airbnb, Atlassian (Jira) et même Wordpress Bien entendu, React est utilisé par les équipes de Facebook et Instagram

Pour autant, l’approche adoptée par React ne fait pas l’unanimité. Pour vous faire un avis, je vous propose dans cet article une brève présentation des principes de base.

Bonne lecture et bon code

Prérequis

Si vous ne savez pas ce qu’est un transpiler, je vous invite à le découvrir avant sur https://babeljs.io/ En quelques mots, un transpiler va transformer le code saisi pour permettre son exécution. Ainsi, vous pouvez utiliser la nouvelle syntaxe ES6 et laisser le transpiler rendre votre code compatible avec d'anciens navigateurs comme ie8.

Je vous propose d’utiliser l’IDE Visual Studio Code de Microsoft pour la suite, bien adapté à ce genre de dev https://code.visualstudio.com/ Bien sûr, vous pouvez utiliser n’importe quel éditeur du moment que vous le maîtrisez suffisamment.

Vous devez également avoir installé NodeJS sur votre poste https://nodejs.org/en/

C'est quoi React ?

React est un projet interne Facebook qui a pour seul objectif de gérer l’UI. On ne trouvera donc pas de système de routing, des appels Ajax etc. Les points forts avancés sont la vitesse de rafraîchissement des interfaces et la synchronisation permanente de ces dernières avec les données.

A l’origine React est utilisé dans un navigateur web, mais la partie chargée du rendu n’est pas intégré à React et c’est avec cette séparation qu’on a pu voir émerger le projet ReactNative qui permet de développer des applications avec React (donc en Javascript) mais en manipulant les composants natifs des OS mobiles iOS et Android

Puisqu’on parle de rendu, React utilise un langage maison appelé le JSX Il s’agit d’une langage proche du XML qui permet de décrire des interfaces sans se soucier du moteur de rendu https://facebook.github.io/jsx/ L’utilisation d’un transpiler est donc nécessaire pour convertir le JSX en un langage interprétable par le navigateur puisque c’est ici notre sujet.

Préparation de l'environnement

création d’un nouveau répertoire pour notre projet, appelé par exemple REACTJS Ce répertoire va contenir les sous-répertoires suivants :

REACTJS/
    | jsx/   ---> contiendra le code react avec la syntaxe JSX
    | js/     ---> contiendra le code JS généré par Babel
    | libs/  ---> contiendra les librairies ReactJS

récupération de react.min.js et react-dom.min.js sur le site https://facebook.github.io/react/ on les place dans le répertoire libs/

installation de babeljs avec nodeJS (dans un terminal)

npm init
npm install babel-cli --save
npm install babel-preset-react --save

Configuration d’une task Visual Studio Code pour convertir à chaque enregistrement le JSX en Javascript. Voici la task en question

{
    "version": "0.1.0",
    "command": "${workspaceRoot}/node_modules/.bin/babel",
    "isShellCommand": true,
    "tasks": [
        {
            "args": ["--presets", "react", "jsx", "--out-dir", "js", "-w", "--source-maps"],
            "taskName": "jsx-convert",
            "suppressTaskName": true,
            "isBuildCommand": true,
            "isWatching": true
        }
    ]
}

On va enfin créer 2 fichiers

REACTJS/jsx/index.jsx
REACTJS/index.html

Il est important de noter que les scripts JSX n'ont pas besoin de l'extention .jsx, vous pouvez laisser .js, mais je trouve personnellement que ça aide à garder de la clarté.

Vous devriez donc avoir l’arborescence suivante (ne pas faire attention au index1.js, il s'agit bien de index.js

Pour finir on va installer une extension Chrome bien pratique https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi/reviews

Important : pour voir l’onglet React dans les outils pour développeurs de Chrome il faut exécuter le code sur un serveur web et non en local

Vu que nodeJs est installé, déplacez vous dans le répertoire de notre projet et faites dans un terminal > http-server lancez ensuite l’url par défaut dans votre navigateur http://localhost:8080

Let's code

index.html

Ici on veut simplement afficher/masquer un texte en fonction de l’état d’une case à cocher

On commence par notre fichier index.html qui est minimaliste

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>reactJS</title>
</head>
<body>    
    <div id="show-hide"></div>
 
    <script src="libs/react.min.js"></script>
    <script src="libs/react-dom.min.js"></script>
 
    <script src="js/index.js"></script>
</body>
</html>

note : vous remarquez qu’on appelle le fichier js/index.js et non celui du répertoire jsx/

index.jsx

Avec React, le principe est de travailler avec des composants qui vont isoler le code On va donc créer un composant ShowHideComponent avec la méthode React.createClass()

Notre composant doit comprendre au moins une méthode : render()

Cette méthode va retourner le morceau de DOM qui va être affiché dans le tag #show-hide

(function(){
    'use strict';
    var ShowHideComponent = React.createClass({
        render: function () {
            return (
                <div>
                    <label>
                        <input type="checkbox" />                        
                        afficher le texte en dessous
                    </label>
                    <p id="citation">
                        - "Marty McFly : Hé, attendez un peu, Doc. 
                        Est-ce que j'ai bien entendu ? Vous dites que vous avez fabriqué 
                        une machine à voyager dans le temps… à partir d'une DeLorean ?"
                    <br/>
                    - "Emmett Brown : Faut voir grand dans la vie ! 
                    Quitte à voyager dans le temps au volant d'une voiture, autant en choisir une qui ait de la gueule !"
                    </p>
                </div>
            );
        } 
    });
 
    ReactDOM.render(
        <ShowHideComponent />,
        document.querySelector('#show-hide')
    )
}());

A noter : Le JSX impose que tous les tag soient fermés, les <br>, <input> et autres doivent donc s’écrire : <br /> <input />

Les tags HTML s’écrivent en minuscules et les composants React commencent avec une majuscule.

Pour afficher le composant, on va utiliser la méthode reactDOM.render() qui prend en paramètres le composant React et le noeud du DOM HTML dans lequel l’insérer.

dans le navigateur

A partir de là, pour voir le contenu d'afficher dans un navigateur, vous devez avoir lancé la tâche de transpilation par Babel du code pour que le code jsx soit converti en javascript

Pour vérifier que ça a fonctionné, il suffit de vérifier la présence du fichier js/index.js

Enfin, vous devez lancer un serveur web en local et comme vous avez nodeJS installé, il suffit, depuis un terminal ou l'invite de commande windows d'aller dans le répertoire du projet de lancer la commande http-server ou node http-server

A partir de là, si vous affichez dans le navigateur l'url : http://localhost:8080

et si tout se passe bien vous deviez avoir ça:

Un composant dans tous ses états

Comme expliqué en intro, une des forces de React est de conserver en permanence l’IHM synchronisée avec les composants et ça s’applique bien entendu aux changements d’état d’une checkbox.

Pour conserver l’état, on va utiliser les states

Pour cela on commence par déclarer les states dans une méthode du framework getInitialState()

Cette méthode retourne un objet qui contient les états du composant à la création de celui-ci.

Pour rester synchro, on pose un écouteur sur la checkbox qui va assurer la synchro à chaque changement.

Pour changer un state, on utilise la méthode setState()

Voici le code complet qu'on va détailler juste en dessous

(function(){
    'use strict';
    var ShowHideComponent = React.createClass({
        // permet d'indiquer l'état par défaut du composant
        getInitialState: function (){
          return {
              isChecked: false
          };  
        },
 
        // evenement déclenché juste avant le rendu du composant
        componentDidMount: function () {
            this.setState({isChecked: this.props.check});
        },
 
        // fonction déclenchée lorsqu'on change l'état de la case à cocher
        cbxOnChange: function (e){
            this.setState({isChecked : e.target.checked});
        },
 
        // la fonction render qui affiche notre composant
        render: function () {
            return (
                <div>
                    <label>
                        <input 
                            type="checkbox"
                            checked={this.state.isChecked}
                            onChange={this.cbxOnChange} />                        
                        afficher le texte en dessous
                    </label>
                    {
                        (() => {
                          if (this.state.isChecked) {
                              return (
                                <p id="citation">
                                    - "Marty McFly : Hé, attendez un peu, Doc. 
                                    Est-ce que j'ai bien entendu ? Vous dites que vous avez fabriqué 
                                    une machine à voyager dans le temps… à partir d'une DeLorean ?"
                                    <br/>
                                    - "Emmett Brown : Faut voir grand dans la vie ! 
                                    Quitte à voyager dans le temps au volant d'une voiture, 
                                    autant en choisir une qui ait de la gueule !"
                                </p>
                              );
                          }  
                        })()
                    }
                </div>
            );
        } 
    });
 
    ReactDOM.render(
        <ShowHideComponent check={true} />,
        document.querySelector('#show-hide')
    )
}());

Il y plusieurs choses à dire sur ce code

Gestion de la case à cocher

Comme expliqué, React garde synchronisé les composants de l'IHM avec un model par le biais d'états, les states

On va donc déclarer un état coché ou non pour notre case

getInitialState: function (){
    return {
        isChecked: false
    };  
}

La méthode getInitialState est une méthode du framework qui permet de déclarer les états par défaut de notre composant.

Elle retourne un objet contenant les états.

Ensuite la case à cocher elle même

<input 
    type="checkbox"
    checked={this.state.isChecked}
    onChange={this.cbxOnChange} />

Pour permettre aux composants React d'être synchro avec leur model, il faut relier ces derniers avec un état (state)

Ici on indique que l'état coché (ou non) dépend de l'état (state) isChecked

Puis, lorsqu'on change l'état de la case à cocher, on appelle la méthode cbxOnchange()

cbxOnChange: function (e){
    this.setState({isChecked : e.target.checked});
}

Cette méthode va simplement modifier l'état (state) isChecked pour refléter l'état actuel de la case à cocher

La boucle est bouclée

Remarque, il est possible d'utiliser une autre syntaxe pour mettre à jour l'état en utilisant les arrow functions

ça donnerait ça

<input 
    type="checkbox"
    checked={this.state.isChecked}
    onChange={(e) => this.setState({isChecked : e.target.checked}) } />

Les arrow functions sont une nouveauté de la norme ES6 (ou ES-2015)

affichage du texte

Le texte est affiché lorsque la case est cochée.

Autrement dit, lorsque le state isChecked est à true

Lorsqu'on change un state par la méthode setState(), React va appeler de nouveau la méthode render()

On va donc, dans cette méthode, conditionner l'affichage du texte à la valeur du state isChecked

Pour cela, on commence par indiquer en plaçant le code entre accolades que ce qui suit est du javascript et doit être exécuté et non affiché

{
}

Entre les accolades, on utilise une Self Invoqued Function, une fonction qui s'exécute immédiatement

{
    (() => {
        // notre code viendra ici
    })()
}

Note, on a utilisé la syntaxe introduite plus haut, on pourrait aussi écrire

{
    (function (){
        // notre code viendra ici
    })()
}

Enfin, on teste la valeur de l'état isChecked pour retourner le texte

if (this.state.isChecked) {
    return (
        <p id="citation">
            - "Marty McFly : Hé, attendez un peu, Doc. 
            [...]
        </p>
    );
}

Pour finir, on va permettre à notre composant d'exposer un attribut qui défini l'état par défaut de la case à cocher, de cette manière, on peut rendre notre composant facilement utilisable dans une application plus grande.

Le passage de paramètre à un composant React se fait par les props

Pour faire simple, les props sont envoyées au composant et ne sont pas sensée changer dans le temps alors que les states représentent tout ce qui va changer pendant la vie du composant React

Pour passer un props au composant, on ajoute simplement un attribut au composant (tout en bas du script)

ReactDOM.render(
    <ShowHideComponent check={true} />,
    document.querySelector('#show-hide')
)

On passe l'attribut check qui a la valeur true

Important, on ne passe pas la chaîne de caractère “true” mais bien un booléen, il faut donc le placer entre accolade pour que React le voit comme du code javascript

Puis c'est dans la méthode du framework componentDidMount qu'on prend en compte l'attribut check pour définir l'état par défaut de la case à cocher

componentDidMount: function () {
    this.setState({isChecked: this.props.check});
}

note : si on ne passe pas d'attribut à notre composant, ça va coincer, on peut alors définir la valeur par défaut de l'attribut par la méthode du framework getDefaultProps

Ce qui donnerait

getDefaultProps: function () {
    return {
        check : false
    }
}

debug

Si vous ne l'avez pas encore fait, ouvrez les outils pour développeur de votre navigateur et si vous avez installé l'extension React, vous avez accès à l'état des props et states !

Conclusion

Voilà, vous savez maintenant un peu plus à quoi ressemble React.

La première réaction pourrait être de dire que ça fait finalement beaucoup de code pour pas grand chose car sans framework, on obtiendrait le même résultat en 3-4 lignes et sans s'encombrer de transpiler

Oui mais React n'est pas fait pour afficher masquer un texte en fonction d'une case à cocher mais bien à gérer des applications complètes écrites en javascript

Donc une fois de plus, il ne s'agit pas de rechercher l'outil miracle qui s'adapte à toutes les situations mais bien d'avoir connaissance des différents outils disponibles et d'utiliser celui le plus approprié.

Avoir une approche besoin et non solution

En savoir plus

Quelques liens intéressant pour poursuivre la découverte de React

http://babeljs.io/docs/plugins/preset-react/

https://facebook.github.io/react/index.html