Premiers pas avec React.js - Partie 2
Dans la première partie de la série "Premiers pas avec React.js" , vous avez vu principalement la configuration de React sur votre ordinateur local.
Dans cette deuxième partie, vous allez découvrir ce que tout programmeur React.js est censé connaître, y compris les cycles de vie, les types de propriétes et les différents composants de React.
I - Les composants
Le concept le plus important à comprendre en React est le composant.
En effet, React est conçu autour du concept de composants réutilisables, vous définissez de petits composants et vous les mettez ensemble pour former de plus gros composants. Tous les composants, petits ou grands, sont réutilisables, même pour différents projets.
Conceptuellement, les composants sont comme des fonctions JavaScript. Ils acceptent des entrées arbitraires (appelées "props"), que nous allons aborder plus en détail après, et renvoient des éléments React décrivant ce qui devrait apparaître à l'écran.
Il existe deux types de composants en React : les composant fonctionnels et les composants à état.
Le composant fonctionnel est une fonction qui prend en paramètre un objet appelé “props” et retourne du JSX :
var HelloWorld = (props) => {( let user = props.user; return <p>Hello { user } </p> )}
Le composant à état (stateful) est une classe JavaScript qui étend de la classe Component de React et qui possède obligatoirement une méthode render retournant du JSX. Il reçoit des props et possède son état interne pour gérer son rendu.
class HelloWorld extends React.Component { constructor(props) { super(props); this.state = { online: false } } render() { const user = this.props.user; return ( <p> Hello {user}, you are {!this.state.online || 'online'} ! </p> ) } }
II - Les props
Vous vous demandiez peut-être d’où vient la variable “this.props.user”, ci-dessus.
Si vous avez déjà écrit une ligne de code HTML, vous connaissez probablement les attributs HTML tel que l’attribut “src” dans la balise <img>. En React les attributs sont connus sous forme de “props” (abréviation de “properties”).
La plupart des composants peuvent être personnalisés avec différents props lors de leur création.
Les props d’un composant sont sous forme d’un objet qui contient des informations sur ce composant. Pour voir les props de ce dernier on utilise l’expression : this.props.
En règle générale, les props sont “immuable’”, donc ne doivent pas être changés.
class Hello extends React.Component { render() { return( <div> <h1>{this.props.text}</h1> </div> ); } }
Les données en React circulent en une seule direction -> du parent à l’enfant. Ainsi, ces props ne doivent pas être modifiés à l'intérieur des composants puisque ces derniers reçoivent des props de leur parent.
Si vous avez des propriétés en tant qu'objet et que vous voulez le passer en JSX , vous pouvez utiliser "..." comme un opérateur "spread" pour passer tout l'objet des propriétés. Par exemples les deux fonctions suivantes sont équivalentes :
function fct1() { return <Person firstName="Ben" job="Designer" />; } function fct2() { const props = {firstName: 'Ben', job: 'Designer' }; return <Person {...props} />; }
Cependant, vous allez sans doute me demander sans ce qui se passe lorsqu’un composant reçoit des données d’une autre source que le parent ? Que faire si l’utilisateur rentre directement les données dans le composant ?
Eh bien, c’est pourquoi nous parlerons du “state”.
III -Les States
Comme les props, le state possède des informations sur le composant, mais le type d’information et la façon dont il est géré sont différentes.
A l'inverse des props, le state est “muable” et donc peut être modifié.
En React, le state est interne à un composant, tandis que les props sont transmis au composant. Il est utilisé dans les composants pour garder une trace des informations entre les différents rendus.
L'état du composant est stocké dans "this.state".
class Counter extends React.Component { constructor(props) { super(props); this.state = {counter: 0}; } }
L'état du composant peut être modifié en appelant :
this.setState(data, callback);
L'argument "data" peut être un objet ou une fonction qui renvoie un objet contenant des clés à mettre à jour. Le callback est optionnel, s'il est fourni il sera appelé après la fin du rendu du composant. Vous aurez rarement besoin d'utiliser ce rappel puisque React prendra soin de garder votre interface utilisateur à jour.
IV- Le cycle de vie d'un composant
Les composants à état cités plus haut possède un cycle de vie qui leur est propre et React.js nous permet d'interagir avec chacun d’eux.
Bien que seul la méthode Render() et le constructor seront appelés, il sera aussi parfois nécessaire de faire appel aux différents cycle de vie et d'interagir avec eux.
Avant d’aller plus loin, il est important de schématiser ce cycle de vie :
Il est maintenant temps de détailler chacun des cycles du composant.
1-Constructor
Le Constructor est invoqué en premier. Il reçoit en argument toutes les props initiales du composant. C’est le moment idéal pour initialiser le state de votre composant grâce à “this.state”. Le Constructor est aussi utilisé pour Binder les events Handler à l’instance.
constructor(props){ super (props); this.action() = this.action.bind(); this.state = { name : “john” } }
2- ComponentWillMount
Avant que le Rendu du composant soit fait, componentWillMount() sera appelé. Bien que cette méthode existe, il n’est pas conseillé d’y faire appel et de plutôt passer par le constructor car vous ne pourrez pas intéragir outre mesure avec composant car n’étant pas monté.
3- ComponentDidMount
Une fois le rendu fait, c’est au tour de componentDidMount() d’être appelée. C’est le moment idéal pour aller chercher les références directes des éléments du DOM. C’est ici que vous pourrez charger toutes les données utiles et relative à votre composant.
4- ComponentWillReceiveProps
Le composant passe par une autre série d’étapes lorsque son parent refait son rendu.
La première étape de cette série est ComponentWillReceiveProps() qui sera appelée avant que quoi que ce soit ne se produise avec les nouvelles props. Ici vous pouvez donc accéder aux futures props mais aussi aux actuelles. C’est l’endroit idéal pour vérifier si vos props vont changer par exemple.
componentWillReceiveProps(nextProps){ if(nextProps.name !== this.state.name){ this.setState({name : nextProps.name}) } }
Si la prochaine Props.name est différente de this.state alors attribuer à this.state.name le nouveau nom.
5- ShouldComponentUpdate
Suite à ça, c’est à shouldComponentUpdate() de rentrer en scène. C’est une étape un peu spéciale du cycle de vie car c’est le moment où le composant demande la permission de faire un nouveau rendu. Vous l’aurez compris shouldComponentUpdate() retourne seulement un boolean qui par défaut sera “true”.
shouldComponentUpdate(nextProps, nextState){ return nextProps.name !== this.state.name }
Si le prochaine props.name n’est pas égale à this.state.name alors le composant se mettra à jour.
6- ComponentWillUpdate
Une fois tout ce processus passé, il est maintenant temps pour le composant d'effectuer un rendu mais avant ça, le ComponentWillUpdate() sera appelé à son tour. Il est similaire au componentWillreceiveProps() bien qu’il ne puisse pas appeler this.state. C’est pourquoi si vous utilisez déjà componentWillReceiveProps(), il ne vous sera pas d’une grande utilité. Son utilité peut faire sens si jamais vous avez besoin de faire quelque chose lorsque les props changent ET que vous utilisez shouldComponentUpdate().
7-ComponentDidUpdate
componetDidUpdate() sera appelé ensuite et pourra vous permettre d'effectuer des changements sur votre composant grâce aux éventuelles nouvelles props reçues.
componentDidUpdate(){ this.action(); }
8- ComponentWillUnmount
Enfin, pour finir, le composant va se démonter, mais avant de partir il vous permettra d’effectuer des actions supplémentaires. componentWillUnmount() vous sera donc utile pour nettoyer vos différents éléments liés à votre composant.
V- Passer des données du parent à l'enfant (Pattern Provider) (provisoire)
Avec React.js tout est question de parent et d’enfants. C’est pourquoi il est essentiel de pouvoir faire passer des données du parent vers le ou les enfant(s). Les données que vous ferez transiter seront stockés dans les props du ou des composant(s) enfant(s) et pourront être utilisées afin d’effectuer un rendu adéquat.
Imaginons un composant qui vous permettra de remplir un remplir un formulaire avec un prénom et un nom et son composant enfant qui lui affichera les informations que vous avez entrées.
import React, { Component } from 'react'; class Formulaire extends Component { constructor(props) { super(props); this.state = { term: '', items: [] }; } onChange = (event) => { this.setState({ term: event.target.value }); } onSubmit = (event) => { event.preventDefault(); this.setState({ term:’’', items: [...this.state.items, this.state.term] }); } render() { return ( <div className="App"> <form onSubmit={this.onSubmit}> <input value={this.state.term} onChange={this.onChange} /> </form> </div> ); } }
A travers ce code, il est question ici de rendre un formulaire qui lors de sa validation ajoutera la valeur contenu dans le this.state.term vers le tableau contenu dans this.state.items.
Commençons par le début avec le constructor. Dans celui-ci, nous initialisons les deux states qui nous seront utiles pour cet exemple à savoir “term” qui va contenir votre saisie actuelle et “items” qui sera un tableau contenant les différentes entrées que nous lui ajouterons depuis le formulaire.
Ensuite, nous retrouvons notre fonction OnChange() qui prendra en argument “event” et qui à chaque changement effectué sur l’input aura pour effet dans un premier temps de mettre à jour le state.term qui lui, si vous regardez bien le code, va gérer la value de cet input.
Pour ce qui est du détail de la fonction onSubmit(), tout d’abord nous faisons appel à eventPreventDefault() qui va empêcher notre formulaire d’effectuer son comportement normal ce qui nous serait nuisible pour faire ce que nous voulons ici. Ensuite, nous appelons this.setState qui dans un premier temps va cleaner this.state.term qui va avoir pour effet de nettoyer le champs qui tire sa valeur de ce dernier. La ligne suivante va avoir pour effet d’ajouter notre this.state.term actuel dans le tableau contenu dans this.state.items
Maintenant si vous regardez bien, à aucun endroit nous faison le rendu de ce que nous venons d’ajouter depuis notre formulaire. Pour pouvoir afficher les entrées de notre tableau qui, je vous le rappelle, est contenu dans this.state.items, nous allons avoir besoin de créer un autre composant qui aura pour fonction d’afficher ces entrées sous forme de liste. (A noter que bien sûr nous aurions pu faire le rendu de cette liste dans notre composant actuel mais pour le bien de la démonstration nous le ferons dans deux composants différents.)
Il est maintenant temps d’afficher notre liste !
import React, { Component } from 'react'; class List extends Component { render(){ let list; list = this.props.items.map((item)=>{ return <li>{item}</li> }) return <div>{list}</div> } } export default List;
Le code est relativement simple, nous effectuons un rendu et appelons la méthode map() qui nous sert à parcourir un tableau et d’en retourner les éléments.
Cependant, il nous manque encore un élément pour que tout fonctionne. Comme vous l’aurez sûrement remarqué, il n’existe pas dans notre composant de props.items, c’est normal, nous devons faire passer les données du parent vers l’enfant pour cela rien de plus simple :
import React, { Component } from 'react'; import List from ‘./list’; class Formulaire extends Component { constructor(props) { super(props); this.state = { term: '', items: [] }; } onChange = (event) => { this.setState({ term: event.target.value }); } onSubmit = (event) => { event.preventDefault(); this.setState({ term:'', items: [...this.state.items, this.state.term] }); } render() { return ( <div className="App"> <form onSubmit={this.onSubmit}> <input value={this.state.term} onChange ={this.onChange} /> </form> <List items={this.props.items} /> </div> ); } }
Il nous suffit donc d’importer notre composant List et d’ensuite y faire appel. Afin de faire passer les données souhaités, ici state.items il nous faut tout simplement lui faire passer les données souhaitées lors de l’appel du composant.
A présent votre petite application marche parfaitement !
Commentaires