Lors de notre introduction en trois parties
à Vue.js, nous avons vu ensemble comment construire une application simple,
en tirant notamment parti du système de templating proposé par le
framework, à base de balises et de directives telles que v-if
et v-for
.
Bien que simple et riche, cette façon de procéder peut-elle toutefois suffire dans tous les cas de figure ? Je vais laisser cette question en suspens et, dans l’intervalle, vous montrer ce que l’on peut faire d’autre pour définir le rendu de nos composants ;)
render
, love me true
Si vous avez déjà utilisé React, le concept d’un composant comprenant une
méthode render
ne vous est probablement pas étranger : c’est cette méthode
que le framework appelle pour obtenir un rendu. Dans un
SFC Vue.js, c’est la section
template
qui remplit cet office, en présentant directement le balisage
correspondant.
L’inconvénient, c’est qu’on se retrouve vite limité si on a besoin de faire beaucoup varier le rendu en fonction de certains critères. Bien sûr, les directives dont je parlais en introduction sont là pour nous donner un peu de souplesse, mais imaginez un composant dont l’objectif est d’effectuer le rendu d’un champ de formulaire :
<TextInput
:multiline="true /* ou false */"
name="something"
value="Coucou"
@change="someMethod"
/>
Note : toute ressemblance avec l’API de React Native serait purement fortuite.
Selon la valeur de la prop multiline
, ce composant sera ultimement traduit,
dans un cas, par :
<textarea
:name="name"
@input="() => $emit('change')"
>{value}</textarea>
Et dans l’autre, par :
<input
type="text"
:name="name"
:value="value"
@input="() => $emit('change')"
/>
Alors, oui, on pourrait effectivement s’en sortir avec un v-if
, mais au prix
de devoir répéter une prop et un event handler, et en tant que bons
développeurs, on n’aime pas trop ça. De plus, vous vous doutez que l’exemple
pris ici est volontairement simple, mais qu’on pourrait avoir bien plus de
duplication de code (props de validité HTML5, class
voire style
, etc.).
Alors, comment faire ? C’est très simple : on oublie la fameuse section
template
, et on ajoute à notre composant… une méthode render
!
export default {
props: {
multiline: Boolean,
name: String,
value: String
},
render(createElement) {}
};
Heu, on fait comment ?
La méthode render
reçoit en paramètre une fonction fournie par Vue.js,
intitulée createElement
, et qui fait bien ce que son nom dit qu’elle fait :
créer programmatiquement un élément. Elle accepte elle-même jusqu’à trois
paramètres :
"div"
), soit une instance de composant Vue (par
exemple, MyComponent
), soit une fonction retournant l’un des deux — quand je
vous disais que c’était souple !class
style
attrs
props
domProps
on
nativeOn
directives
scopedSlots
slot
key
ref
createElement
le cas échéant — s’il n’y en a qu’un, il est possible
de le passer directement.Tout cela doit vous paraître quelque peu indigeste de prime abord, notamment en ce qui concerne l’utilisation de l’objet de paramétrage, mais poursuivons si vous le voulez bien avec notre exemple, ce qui devrait commencer à lever le voile !
render(createElement) {
const onInput = () => this.$emit("change");
if (this.multiline) {
return createElement("textarea", {
attrs: {
name: this.name
},
on: {
input: onInput
}
}, this.value);
}
return createElement("input", {
attrs: {
type: "text",
name: this.name,
value: this.value
},
on: {
input: onInput
}
});
}
Comme vous pouvez le voir, on procède finalement ici à un strict équivalent de
ce qu’on aurait réalisé dans template
, avec une syntaxe plus « bas niveau »
mais infiniment plus souple, ce qui la rend plus adaptée à ce genre de cas de
figure.
Il existe un outil qui peut nous permettre de conserver cette souplesse tout en gagnant en lisibilité : j’ai nommé JSX !
Bien connue elle aussi des utilisateurs de React, puisqu’elle a été introduite par ce dernier, il s’agit d’une autre syntaxe XML-like que celle des composants Vue, offrant davantage de liberté puisqu’on peut y interpoler à l’infini markup et code JavaScript.
Ce parti pris a ses avantages et ses inconvénients ; pour afficher
conditionnellement un élément, par exemple, avec la syntaxe « habituelle »,
vous utiliseriez v-if
:
<div v-if="someCondition">Hide and seek</div>
En JSX, point de directives, et point de structures de contrôle classiques non
plus (typiquement, if
) : il est nécessaire d’utiliser directement des
expressions, et donc en l’occurrence de ruser avec une condition ternaire :
{someCondition ? <div>Hide and seek</div> : null}
Pour ce qui est des boucles, Vue utilise, vous le savez (n’est-ce pas ?),
v-for
:
<ul><li v-for="item in collection" :key="item.id">{item.name}</li></ul>
En JSX, il vous faudra utiliser Array.prototype.map
, ou toute autre
expression référençant un tableau ou autre itérable :
<ul>{collection.map(item => <li key={item.id}>{item.name}</li>)}</ul>
Il existe bien sûr d’autres différences, notamment la manière de passer une
valeur dynamique à un attribut (:key="value"
pour Vue, key={value}
pour
JSX) comme vous pouvez le voir ci-dessus.
Quoi qu’il en soit, sachez (si vous ne l’avez pas encore deviné) qu’il est
possible d’utiliser JSX
dans la méthode render
d’un composant Vue !
render(h) { // renommer createElement en h est requis pour JSX
const onInput = () => this.$emit("change");
return this.multiline
? <textarea
name={this.name}
onInput={onInput}
>{this.value}</textarea>
: <input
type="text"
name={this.name}
value={this.value}
onInput={onInput}
/>;
}
Je vois pas trop l’intérêt, on répète de nouveau les props !
Tu as tout à fait raison : pour ce cas précis, l’intérêt d’utiliser JSX est discutable. Cela aura au moins eu le mérite de te le faire découvrir, d’autant plus qu’il est fort possible que nous en reparlions bientôt (mais c’est un secret).
Nous avons fait un bref tour d’horizon des possibilités de rendering avancé avec Vue.js ; je ne suis pas rentré dans les détails techniques de l’API par souci de brièveté, mais si vous souhaitez expérimenter sur le sujet, n’hésitez pas à consulter la page idoine de la documentation, très complète.
Je vous retrouve très prochainement avec un nouvel article sur Vue.js !
L’équipe Synbioz.
Libres d’être ensemble.
Nos conseils et ressources pour vos développements produit.