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 :

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 :

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.

javascript
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 :

javascript
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é :

javascript
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 false

Maintenant, 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 :

javascript
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.

javascript
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 :

javascript
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