Le hoisting au service des composants React
À première vue, le titre est un peu barbare. Pas d’inquiétude, nous allons commencer par découvrir ce qu’est le hoisting et dans un deuxième temps nous verrons quel peut être son intérêt pour les composants React.
Hissez haut ! Santiano 🎵
Pour découvrir le hoisting, ou “hissage” en français, nous allons partir du code suivant.
print("Il s'agirait de grandir")
function print(log) {
console.log(log)
}
// Ce code affiche : "Il s'agirait de grandir"
Même si la fonction print
est déclarée après avoir été appelée ce code fonctionne.
Cela vient du fait que Javascript va “remonter” les déclarations de fonctions en haut du code. Dans la réalité, le code reste à sa place, mais est stocké en mémoire afin de pouvoir être appelé partout.
Explication issue de la MDN.
Conceptuellement, par exemple, une définition stricte du hissage suggère que les déclarations de variables et de fonctions sont déplacées physiquement en haut de votre code, mais ce n’est pas ce qui se passe en fait. A la place, les déclarations de variables et de fonctions sont mises en mémoire pendant la phase de compilation, mais restent exactement là où vous les avez tapées dans votre code.
Transformons le code précédent en utilisant une fonction fléchée.
print("Il s'agirait de grandir")
const print = (log) => {
console.log(log)
}
// Ce code affiche : "Uncaught ReferenceError: Cannot access 'print' before initialization"
Avec const
et let
la remonté a lieu mais pas l’initialisation. En d’autres termes appeler print
ne générera pas une erreur du type print is not defined
. En revanche, print
n’a pas été initialisé, donc il correspond à rien.
Au sein de React
Je me suis longtemps demandé quelle syntaxe privilégier pour les composants fonctionnels.
const Button = ({ value, onClick }) => {
return <button onClick={onClick}>{value}</button>
}
// ou
function Button({ value, onClick }) {
return <button onClick={onClick}>{value}</button>
}
Étant donné que l’on a parlé du hoisting juste avant, vous vous doutez que la seconde forme a un avantage sur la première.
On peut trouver un intérêt dans la déclaration des propTypes
et des defaultProps
.
Avec une fonction fléchée.
import React from "react"
import PropTypes from "prop-types"
const Button = ({ value, onClick }) => {
return <button onClick={onClick}>{value}</button>
}
// Nécéssairement en dessous du composant
Button.propTypes = {
value: PropTypes.string,
onClick: PropTypes.func.isRequired,
}
Button.defaultProps = {
value: "",
}
export default Button
Avec une fonction “normale”.
import React from "react"
import PropTypes from "prop-types"
// Peut être déplacé au dessus du composant
Button.propTypes = {
value: PropTypes.string,
onClick: PropTypes.func.isRequired,
}
Button.defaultProps = {
value: "",
}
function Button({ value, onClick }) {
return <button onClick={onClick}>{value}</button>
}
export default Button
Les fonctions nous laissent le choix et nous permettent ainsi de réorganiser notre code en plaçant la signature du composant au début du fichier.
Conclusion
Il y a une chose à ne pas oublier lorsque l’on utilise React : “C’est juste du JS”. Tous les concepts que l’on connait sont valides et tous ceux que l’on découvrira le seront.
Grace au hoisting on peut arranger notre code de façon à avoir directement accès à la signature de notre composant. Cela évite de devoir scroller en bas de fichier pour savoir quelles sont les props
que l’on peut utiliser.
Une question demeure : faut-il utiliser cette astuce ?
Faites en fonction de vos préférences.
Personnellement je l’utilise mais ce n’est en rien une règle absolue.
Merci de m’avoir lu.