React est devenu une référence dans le monde des développeurs front-end. Il a même su s’imposer au sein des back-end grâce à NodeJS et aux systèmes d’isomorphisme. Réagir se positionne principalement en concurrent direct d’Angulaire et de Vue bien que ce dernier soit arrivé plus tard et ce soit fortement inspiré de React. Angulaire se présente comme un véritable cadre avec tous ses outils ainsi que d’une arborescence définie. Du côté de React, il est difficile d’en dire autant. Ce n’est pas un framework, il s’agit d’un outils et par conséquent il est beaucoup plus flexible. Il sera plus adapté pour implémenter des briques isolés de votre page. React est un formidable outils, d’autant plus qu’avec la surcouche JSX, il devient très agréable de développer avec. L’association avec Redux permet de décupler les possibilités. Petit tour d’horizon !
React
Réagir est un système permettant de faire de le rendu de composants. Un peu à la manière d’un DOM, des composants contiennent d’autres composants. La mise à jour d’un composant entraîne la mise à jour des composants enfants en cascade. Réagir utiliser le VirtualDOM ce qui représente l’un de ses plus forts atouts en terme de performance.
JSX
React peut s’écrire avec la « véritable syntaxe » JavaScript mais cela est moins facile à écrire et encore moins à lire. JSX apporte un véritable souplesse dans l’écriture, dans la lecture et la compréhension. Babel proposer un présélectionner pour JSX ce qui permet de transpiler le JSX en code JavaScript classique et exécutable par le navigateur.
Sans JSX
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
classe Bonjour s’étend React.Composant { render() { return React.createElement( ‘div’, nul, React.createElement( ‘h1’, nul, Titre ), React.createElement( ‘p’, nul, Description ) ) ; } } |
Avec JSX
1 2 3 4 5 6 7 8 9 10 |
classe Bonjour s’étend React.Composant { render() { return < ;div> ; < ;h1> ;Titre</h1> ; < ;p> ; Description </p> ; </div> ; } } |
ES2015
Autant se le dire maintenant, React utilise tous les avantages et nouveautés de ES2015 (anciennement appelé ES6). Sans ES2015, vous devrez écrire un code bien moins buvable. Il est fortement conseillé d’utilisé ES2015 et de le transpiler grâce à Babel.
ECMAScript 5
1 2 3 4 5 6 7 8 |
var Hello = React.createClass({ getInitialState: fonction() { retour {} ; }, rendu: fonction() { retour < ;h1> ;Bonjour, {this.props.name}</h1> ;; } }) ; |
ECMAScript 2015 (ES6)
1 2 3 4 5 6 7 8 9 10 11 |
classe Bonjour s’étend React.Composant { constructeur(props) { super(accessoires) ; ce.state = {} ; } render() { return < ;h1> ;Bonjour, {this.props.name}</h1> ;; } } |
CommonJS vs. Module ES2015
Pour utiliser ES2015, il vous sera fortement conseillé d’utiliser la norme CommonJS ou les modules ES2015. Pour rappel, CommonJS est la nomenclature utilisée par Node.js. Cela permet de facilement découper son code et d’utiliser des composants externes. Cela n’est pas une obligation même si ignorer leur intérêt vous fera perdre de nombreuses heures. Du côté des outils, Browserify compiler du CommonJS (la norme actuellement). webpack lui compile les deux.
Syntaxe CommonJS
1 |
const React = exiger( » réagir « ) ; |
Syntaxe ES2015
1 |
importation {Composant} de réagir ; |
Personnellement, j’aimerai utiliser le standard défini (soit les modules ES2015) mais CommonJS s’est fortement imposé grâce à Node.js. Dans certains cas, un module peut être fonctionnel pour Node.js (back-end) ainsi que dans le navigateur (front-end). De plus, même si dans la majorité des cas, un module peut être fonctionnel avec CommonJS et ES2015, il arrive parfois qu’on rencontre des problèmes d’import avec ES2015.
Exemple d’utilisation avec 2 composants
Liste des composants.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const React = exiger( » réagir « ), Objet = exiger( » ./item.jsx « ) ; classe Liste s’étend React.Composant { render() { return < ;ul> ; {this.props.items.map((item) => ; < ;Article contenu={item.content} /> ;)} </ /ul> ;; } } module.exports = List ; |
Composant Item.jsx
1 2 3 4 5 6 7 8 9 10 11 |
const React = exiger( » réagir « ) ; classe Article s’étend React.Composant { render() { return < ;li> ; {this.props.content} </li> ;; } } module.exports = Item ; |
Génération de l’UI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const React = exiger( » réagir « ), ReactDOM = exiger( » react-dom « ), Liste = exiger( » ./list.jsx « ), articles = [{ content: « Foo » }, { content: « Bar » }, { content: « Baz » }]; ReactDOM.render( < ;Liste articles={items} /> ;, document.getElementById( » container « ) ) ; |
Redux
Redux se présente comme un système de centralisation des données et des actions. React est particulièrement convaincant lorsqu’on commence mais on se retrouve rapidement confronté à certains problèmes de conceptions lorsque nos applications deviennent un peu plus élaborer qu’une simple liste. Par exemple, admettons que nous ayons divers composants au sein de notre page mais qu’ils doivent partager certaines propriétés, nous nous retrouvons rapidement dans l’impasse. Redux propose une solution qui n’est pas toujours facile à comprendre sur le site.
Principe
Dans Réagir, on distingue deux types de données :
- Les propriétés (props) qui sont accessibles uniquement en lecture seule
- L’état (state) qui est disponible en lecture/écriture mais qui reste propre à un composant (local).
La modification du état local ou la réception de nouvelles propriétés (mise à jour du composant) entraîne un rafraîchissement de l’UI.
Avec Redux, on ajoute la notion de store. Un magasin est global. Il contient toutes les informations de tous les composants qui y sont rattachés. Lorsqu’un composant A lance une action et entraîne une modification du store (dit aussi « state global »), le composant B aura également les nouvelles données du composant A. Chaque composant peut mettre en place des comportements différents en fonction de l’état des autres.
Le store va également contenir les actions disponibles dans les composants.
Mise en place
Techniquement, il est possible de mettre en place React et Redux de manière manuelle mais il existe une autre méthode qui permet de découper son code plus proprement et de profiter de certains mécanismes automatiques.
Exemple de mise en place
Arborescence
main.js
sera votre fichier d’entrée. components
contiendra tous vos composants. Le dossier redux
contiendra deux fichiers pour centraliser la partie métier de votre application.
Ce découpage doit bien évidemment être affiné en fonction de la taille de votre application.
1 2 3 4 5 6 7 8 |
./ |_ main.js |_ composants |_ list.jsx |_ item.jsx |_ redux |_ actions.js |_ reducers.js |
Point d’entrée
Dans votre fichier main.js
nous allons monter notre composant Liste et instancier le fournisseur Redux de manière à interfacer notre composant Liste et un magasin Redux.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
const Liste = exiger( » ./composants/list.jsx « ), Fournisseur = exige( » react-redux « ).Provider, React = exiger( » réagir « ), ReactDOM = exiger( » react-dom « ), réducteurs = exiger(« ./redux/reducers.js « ), Redux = exiger( » redux « ) ; let magasin = null; module.exports = () => ; { store = Redux.createStore( reducers, { articles: [] } ) ; ReactDOM.render( < ;Fournisseur magasin={store} > ; < ;Liste/> ; </Fournisseur> ;, document.getElementById( » container « ) ) ; } ; |
Composants
Liste des composants
Le composant Liste possède le même comportement mais au lieu d’exporter le composant, on exporte une instance de react-redux
qui injectera le état global (propriétés du magasin Redux) dans le composant Liste.
deleteItem
est une action qui est déclarée dans le fichier actions.js. Cette action sera disponible dans les propriétés.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
const actions = exiger( » ./redux/actions.js « ), Objet = exiger( » ./item.jsx « ), Réagir = exiger( » réagir « ), ReactRedux = exiger( » react-redux « ) ; classe Liste s’étend React.Composant { render() { return < ;ul> ; {this.props.items.map((item) => ; < ;Article contenu={item.content} deleteItem={this.props.deleteItem.bind(null, élément)} /> ;)} </ /ul> ;; } } module.exports = ReactRedux.connect( (state = {}) => ; state, (dispatch, props) => ; Object.assign({}, props, { deleteItem : actions.deleteItem.bind(null, dispatch) }) )(Liste) ; |
Composant Item
Le composant Article ne change pas réellement. Voici simplement le composant avec l’utilisation de l’action deleteItem
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const React = exiger( » réagir « ) ; classe Article s’étend React.Composant { render() { return < ;li> ; {this.props.content} < ;a onClick={this.props.deleteItem}> ; Supprimer </a> ; </li> ;; } } module.exports = Item ; |
Gestion des actions
Les actions vont être stockées dans le fichier redux/actions.js
.
1 2 3 4 5 6 7 8 9 10 |
fonction deleteItem(envoi, article) { dispatch({ type: » REMOVE_ITEM « , article: article }) ; } module.exports = { deleteItem: deleteItem } ; |
Les réducteurs
Le réducteurs vous permet de gérer la mise à jour des données. Le réducteurs et les actions sont complémentaires. Les traitements comme les requêtes sont réalisées dans le fichier actions.js
et le réducteurs s’occupent de mettre à jour les données du store (state global).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
fonction réducteur(état, action) { const newState = Objet.assign({}, state) ; commutateur (action.type) { cas » REMOVE_ITEM « : const index = newState.items.indexOf(action.item) ; si (index !== -1) { newState.items.splice(index, 1) ; } pause; défaut: retour état ; } retour newState ; } module.exports = reducer ; |
Conclusion
React est un outils puissant mais qui manque rapidement de fonctionnalités de gestion lorsqu’on travaille sur des comportements plus avancés qui impliquent plusieurs composants distants. Redux propose un système intéressant et normalisant. L’utilisation du package react-redux
et du Fournisseur Redux simplifie grandement l’implémentation des interfaces.