React

Une bibliothèque pour réaliser des interfaces web mais pas seulement

Julien M’Poy

February16, 2018

Sommaire

  • Qu’est-ce que React?
  • Composant React
  • Hello World
  • Propriétés d’un composant
  • État d’un composant
  • Lifecycle Hooks
  • Surprises et subtilités
  • Outils et bibliothèques complémentaires
  • Alternatives
  • Avantages et inconvénients de React
  • Questions

Qu’est-ce que React?

  • Bibliothèque Javascript pour créer des interfaces web.
  • Développé par Jordan Walke chez Facebook en 2011 (opensourcé en 2013).
  • Inspiré d’XHP et E4X.
  • Utilisé par Facebook, Netflix, Imgur, Feedly et bien d’autres.

Compétences requises

Caractéristiques de React

  • Composants (Components) graphiques décrivant chaque partie de l’interface.
  • JSX (XML dans du JavaScript)
  • Virtual DOM

Composant React – Component

  • Classe ou fonction JavaScript.
  • Un composant a son propre Virtual DOM.
  • Il contient des React Elements (<div>, <p>, …) ou d’autres composants React.
  • Tout composant retourne son Virtual DOM lorsqu’il est monté (méthode render() dans le cas d’un classe)

Hello World

Dans notre fichier index.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World</title>
</head>
<body>
<div id="root">
<!--
The app component will be mounted here.
Have a look in the ReactDOM.render call in index.js
-->
</div>
<script type="text/javascript" src="js/index.js"></script></body>
</html>

Hello World

Dans notre fichier index.js:

import React from 'react';
import ReactDOM from 'react-dom';
/*
* Toggle comment between these two imports to use either
* the object oriented variant or the functionnal variant.
*/
import App from './AppFunction.js';
// import App from './AppClass.js';
ReactDOM.render(<App />, document.getElementById('root'));

Hello World: variante fonctionnelle

import React from 'react';
const App = props => {
return (
<div>
<h1>Hello World!</h1>
<p>This is a simple functionnal component!</p>
</div>
);
};
export default App;

Hello World: variante orientée objet

import React, {Component} from 'react';
class App extends Component {
render() {
return (
<div>
<h1>Hello World!</h1>
<p>This is a simple class component!</p>
</div>
);
}
}
export default App;

Hello World

Déroulement de l’exécution:

  1. Chargement du script index.js.
  2. Chargement du composant.
  3. ReactDOM «monte» le composant.
  4. Création du DOM virtuel (Virtual DOM).
  5. Appel de render() et affichage du DOM final dans le <div>.

Propriétés – Props

  • Affichage dynamique du composant en fonction de ses propriétés (templating).
  • Passage de valeurs entre composants parents et composants enfants.

Templating

import React from 'react';
/*
* Toggle comment between these two imports to use either
* the object oriented version or the functionnal
* version.
*/
import AnimalsList from './components/AnimalsList.js';
// import AnimalsList from './containers/AnimalsList.js';
const ANIMALS = [
{name: 'Chocolate Lion'},
{name: 'Bad Cat'},
{name: 'Octopus'},
{name: 'Dog'},
];
const App = props => {
return (
<div>
<AnimalsList title="My Animals" animals={ANIMALS} />
</div>
);
};
export default App;

Templating: variante fonctionnelle

import React from 'react';
const AnimalsList = props => {
return (
<div>
<h1>{props.title}</h1>
<ul>
{props.animals.map((item, index) => {
return <li key={index}>{item.name}</li>;
})}
</ul>
<p>The functionnal version rendered this list.</p>
</div>
);
};
export default AnimalsList;

Le templating côté JavaScript se fait avec { }.

Templating: variante orientée objet

import React, {Component} from 'react';
class AnimalsList extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>{this.props.title}</h1>
<ul>
{this.props.animals.map((item, index) => {
return <li key={index}>{item.name}</li>;
})}
</ul>
<p>The class version rendered this list.</p>
</div>
);
}
}
export default AnimalsList;

Propriétés utiles

  • this.props.children

Propriété children

Dans notre index.js:

import React from 'react';
import ReactDOM from 'react-dom';
const MyComponent = props => {
return <div>{props.children}</div>;
};
const App = props => {
return (
<MyComponent>
<h1>First child</h1>
<p>Second child</p>
<p>Third child</p>
</MyComponent>
);
};
ReactDOM.render(<App />, document.getElementById('root'));

État – State

Un composant peut posséder un état (stateful) ou non (stateless).

  • stateful
    • Class components
  • stateless
    • React Elements
    • Functionnal Components

État

En général:

  • Un component est un composant stateless. Souvent une fonction avec des propriétés.
  • Un container est un composant stateful. Souvent une classe avec un état et éventuellement des propriétés.

État

  • component
    • Responsable de la présentation de l’information.
    • Rôle proche d’une vue dans un pattern MVC.
  • container
    • Contient un ou plusieurs composants.
    • Possède une logique propre (AJAX, middleware, etc.).
    • Comportement semblable à un contrôleur dans un pattern MVC ou un ModelView dans un pattern MVVM.

État

  • Contient l’information propre au composant.
  • Rendu du component en fonction de son état.
  • L’état se modifie avec this.setState.
  • Un changement d’état appelle automatiquement la méthode render().

État

Dans notre index.js:

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
class Counter extends Component {
constructor(props) {
super(props);
// Set the default state in the constructor
this.state = {counter: 0};
/* "this" is problematic for events handling
* in the render method that's why we have to use
* "bind"
*/
this.incrementCounter = this.incrementCounter.bind(this);
this.decrementCounter = this.decrementCounter.bind(this);
this.resetCounter = this.resetCounter.bind(this);
}
incrementCounter() {
this.setState({counter: this.state.counter + 1});
}
decrementCounter() {
this.setState({counter: this.state.counter - 1});
}
resetCounter() {
this.setState({counter: 0});
}
render() {
var isPeer = this.state.counter % 2 == 0 ? 'peer' : 'even';
return (
<div>
<h1>State and events</h1>
<p>counter: {this.state.counter}</p>
<p>The counter value is {isPeer}.</p>
<button type="button" onClick={this.incrementCounter}>
Increment
</button>
<button type="button" onClick={this.decrementCounter}>
Decrement
</button>
<button type="button" onClick={this.resetCounter}>
Reset
</button>
</div>
);
}
}
ReactDOM.render(<Counter />, document.getElementById('root'));

Propriétés vs État

  • Les propriétés sont définies au moment de la création du composant.
  • L’état possède un état initial au moment où il est créé mais l’état peut changer après la création du composant. (≠ propriétés)

Lifecycle hooks

  • componentDidMount: appelée la première fois que le component est «dessiné» (render).
  • componentWillUnmount: appelée lorsque le component va être démonté/supprimé.
  • Il en existe d’autres.

Lifecycle hooks

Ces méthodes existent pour ne pas faire de tâches susceptibles de prendre du temps dans le constructeur (eg. allocation/destruction de ressources, AJAX, etc.).

L’affichage du component ne doit pas être retardé par une de ces tâches.

Surprises et subtilités

Surprises et subtilités: attributs HTML error

class MyComponent extends React.Component {
render() {
return (
<div class="form-component">
<h1>Hello world</h1>
<p>Hello! It's me! Your first component!</p>
<form>
<label for="message">Message : <label>
<input id="message" name="message" value="">
</form>
</div>
);
}
}
ReactDOM.render(
<MyComponent />, document.getElementById('my-component')
);

Surprises et subtilités: attributs HTML

class,for, this, with et switch sont des mots réservés en JavaScript. Il faut utiliser className et htmlFor pour palier à ce problème. React s’occupe de faire la transformation pour nous.

Surprises et subtilités: attributs HTML done

class MyComponent extends React.Component {
render() {
return (
<div className="form-component">
<h1>Hello world</h1>
<p>Hello! It's me! Your first component!</p>
<form>
<label htmlFor="message">Message : <label>
<input id="message" name="message" value="">
</form>
</div>
);
}
}
ReactDOM.render(
<MyComponent />, document.getElementById('my-component')
);

Surprises et subtilités: gestion des évènements

On ne peut pas utiliser this.eventHandlerMethod pour gérer les évènements dans render sans utiliser bind dans le constructeur.

Il existe d’autres solutions que bind.

Surprises et subtilités: gestion des évènements

On utilise onClick comme équivalent à onclick, onBlur pour onblur, onMouseOver pour onmouseover, etc.

Un grande partie des évènements sont supportés et il suffit généralement d’utiliser le nom de l’évènement en version camelCase pour l’utiliser (liste exhaustive des évènements supportés).

Exercices

  • Formulaire simple avec un titre changeant dynamiquement.
  • Todo list
  • Kanban sans drag’n drop.

Outils dédiés à React

React sur mobile

  • Avec React Native.
  • Une grande partie des bibliothèques «React friendly» et autres bibliothèque JavaScript sont utilisables sur mobile avec React Native.

Bibliothèques «React friendly»

Bibliothèques «React friendly»

Alternatives

Avantages

  • Assez simple à prendre en main.
  • Composants d’interface réutilisables.
  • Possibilité de stocker et modifier les informations à l’aide des états.

Avantages

  • On ne se bat plus avec DOM et jQuery.
  • Applications de petite taille comparées à des applications faites avec Angular 2 si on compare la taille du JavaScript généré.

Inconvénients

  • React n’est pas un framework. Utilisez d’autres bibliothèques/ frameworks supplémentaires en fonction de vos besoins.
  • Utilisez un autre framework web pour la partie backend.
  • Si l’utilisateur désactive JavaScript, plus rien ne s’affiche.

Questions ?

Liens utiles

Références

Références

Annexes

Installation

Procédure assez simple:

$ npm install -g create-react-app
$ create-react-app my-app
$ cd my-app
$ npm run start

En voiture Simone!