Utilitaires
Le Markup offre de nombreuses fonctions utilitaires qui vous aident à créer des modèles ou à travailler avec le DOM en général :
- element : permet de créer facilement des éléments DOM ;
- suspense : vous permet de rendre le contenu paresseux ;
- repeat : permet de gérer des listes ou de répéter du contenu ;
- when : vous permet de restituer du contenu de manière conditionnelle ;
- visible : vous permet de différer le rendu jusqu'à ce que les éléments entrent dans la fenêtre d'affichage ;
- is and isNot : permet de vérifier rapidement la véracité des états
- and, or, & oneOf : vous permet de vérifier rapidement les conditions des états
- pick : vous permet de lire en profondeur les valeurs clés des objets d'état
Pourquoi avez-vous besoin d'utilitaires ?
Dans Markup, les fonctions sont des citoyens de première classe, ce qui signifie que les données réactives sont représentées par des fonctions. Pour plus de simplicité, vous pouvez créer des fonctions qui gèrent une logique spécifique en dehors du modèle afin que les choses paraissent propres et que la logique soit réutilisable.
Vous pouvez créer des fonctions utilitaires pour gérer des choses telles que :
- validation;
- transformation des données ;
- rendu de base logique ;
- mise en cache ;
- etc. ;
Il vous suffit de définir des utilitaires lorsque vous travaillez avec des états. Tout le reste peut rester sous forme de données statiques.
Les utilitaires ne sont que des fonctions rendues dans un modèle et qui doivent être appelées chaque fois que l'état dont ils dépendent change.
Utilitaire personnalisé
La puissance du travail avec les états et les modèles apparaît lorsque vous commencez à définir vos propres utilitaires. Regardons un exemple rapide :
Nous avons un scénario courant dans lequel nous avons un champ de saisie qui utilise l'état et nous devons afficher un certain message, que la valeur soit valide ou non.
const [value, updateValue] = state(null)
const handleChange = (event) => {
updateValue(event.target.value)
}
html` <input value="${value}" oninput="${handleChange}" /> `.render(
document.body
)Nous pourrions simplement continuer et ajouter la logique du message directement dans le modèle :
html`
<input value="${value}" onchange="${handleChange}" />
${() => {
if (/[a-z]{3,}/i.test(value())) {
return ''
}
return 'Value must me at least 3 characters'
}}
`.render(document.body)Ce n'est pas mauvais, mais la logique du modèle prend de la place et beaucoup d'entre eux rendent le modèle difficile à lire.
J'ai réalisé que je voulais marquer le champ en rouge lorsque l'entrée n'est pas valide et cela repose sur la même logique que nous avons dans la fonction. Ainsi, je peux extraire cette logique dans une fonction pour la réutilisabilité :
const [value, updateValue] = state(null)
const isPristine = () => value() === null
const isValidValue = () => /[a-z]{3,}/i.test(value())
const handleChange = (event) => {
updateValue(event.target.value)
}
html`
<input value="${value}" oninput="${handleChange}" />
${isPristine} ${isValidValue}
`.render(document.body)
// renders: <input> true falseMaintenant, j'ai deux utilitaires qui me disent si la valeur a déjà été modifiée ou si elle est valide et que je peux l'utiliser n'importe où pour restituer n'importe quoi.
Mais je n'ai pas besoin de m'arrêter là, je peux utiliser une fonction pour représenter tout ce que je veux et obtenir quelque chose comme ceci :
const [value, updateValue] = state(null)
const isPristine = () => value() === null
const isValidValue = () => /[a-z]{3,}/i.test(value())
const valueCSSColor = () => (or(isPristine, isValidValue)() ? 'inherit' : 'red')
const handleChange = (event) => {
updateValue(event.target.value)
}
html`
<input
value="${value}"
oninput="${handleChange}"
style="color: ${valueCSSColor}"
/>
${when(
or(isPristine, isValidValue),
html`<p>Your name</p>`,
html`<p style="color: ${valueCSSColor}">
Name must be at least 3 characters
</p>`
)}
`.render(document.body)Vous pouvez voir que nous avons des fonctions qui gèrent différentes logiques qui les composent pour une logique encore plus complexe dépendant de l'état.
Cette capacité à simplement créer et composer des fonctions pour tout gérer est ce qui rend la création de modèles facile et amusante dans Markup.
Nous pouvons aller plus loin en encapsulant tout dans un utilitaire réutilisable pour gérer les valeurs d'entrée de formulaire de toute nature que nous pouvons utiliser avec plusieurs champs de formulaire.
const formFieldValue = (pattern) => {
const [value, updateValue] = state(null)
const isPristine = () => value() === null
const isValid = () => pattern.test(value())
const isPristineOrValid = or(isPristine, isValid)
const color = () => (isPristineOrValid() ? 'inherit' : 'red')
return {
value,
updateValue,
color,
isPristine,
isValid,
isPristineOrValid,
}
}Et cela me permet de créer facilement des gestionnaires de champs pour n'importe quel champ comme ceci :
const name = formFieldValue(/[a-z]{3,}/i)
const email = formFieldValue(/[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i)
const handleNameChange = (event) => {
name.updateValue(event.target.value)
}
const handleEmailChange = (event) => {
email.updateValue(event.target.value)
}
html`
<input
type="text"
value="${name.value}"
oninput="${handleNameChange}"
style="color: ${name.color}"
/>
${when(
name.isPristineOrValid,
html`<p>Your name</p>`,
html`<p style="color: ${name.color}">
Name must be at least 3 characters
</p>`
)}
<input
type="email"
value="${email.value}"
oninput="${handleEmailChange}"
style="color: ${email.color}"
/>
${when(
email.isPristineOrValid,
html`<p>Your email</p>`,
html`<p style="color: ${email.color}">Email is not valid</p>`
)}
`.render(document.body)Comme vous pouvez le constater, en matière de réactivité, Markup s'appuie fortement et uniquement sur des fonctions pour faire le travail. Cette nature orientée fonction rend la création de modèles simple et familière à tous. Essayez-le !
modifier ce document