Utilidades

Markup ofrece muchas funciones de utilidad que le ayudarán a crear plantillas o trabajar con el DOM en general:

¿Por qué necesitas utilidades?

En Markup, las funciones son ciudadanas de primera clase, lo que significa que los datos reactivos se representan con funciones. Para simplificar, puede crear funciones que manejen lógica específica fuera de la plantilla para que todo se vea limpio y la lógica sea reutilizable.

Puede crear funciones de utilidad para manejar cosas como:

Sólo necesita definir utilidades cuando trabaja con estados. Todo lo demás puede permanecer como datos estáticos.

Las utilidades son solo funciones que se representan en una plantilla y que deben llamarse cada vez que cambia el estado del que dependen.

Utilidad personalizada

El poder de trabajar con estados y plantillas surge cuando comienzas a definir tus propias utilidades. Veamos un ejemplo rápido:

Tenemos un escenario común en el que tenemos un campo de entrada que usa estado y necesitamos mostrar un mensaje determinado, ya sea que el valor sea válido o no.

javascript
const [value, updateValue] = state(null)

const handleChange = (event) => {
    updateValue(event.target.value)
}

html` <input value="${value}" oninput="${handleChange}" /> `.render(
    document.body
)

Podríamos seguir adelante y agregar la lógica del mensaje directamente en la plantilla:

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)

Esto no está mal, pero la lógica de la plantilla ocupa espacio y muchas de ellas dificultan la lectura de la plantilla.

Me di cuenta de que quiero marcar el campo en rojo cuando la entrada no es válida y eso se basa en la misma lógica que tenemos en la función. Entonces, puedo extraer esa lógica en una función para su reutilización:

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

Ahora tengo dos utilidades que me dicen si el valor ha cambiado alguna vez o si es válido y puedo usarlo en cualquier lugar para representar lo que sea.

Pero no necesito detenerme ahí, puedo usar funciones para representar cualquier cosa que quiera y terminar con algo como esto:

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)

Puede ver que tenemos funciones que manejan diferentes lógicas y las componen para una lógica aún más compleja que depende del estado.

Esta capacidad de simplemente crear y componer funciones para manejar todo es lo que hace que la creación de plantillas sea fácil y divertida en Markup.

Podemos mejorar las cosas envolviendo todo en una utilidad reutilizable para manejar valores de entrada de formulario de cualquier tipo que podamos usar con múltiples campos de formulario.

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,
    }
}

Y esto me permite crear fácilmente controladores de campos para cualquier campo como este:

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)

Como puede ver, cuando se trata de reactividad, Markup depende en gran medida y únicamente de funciones para realizar el trabajo. Esta naturaleza orientada a funciones hace que las plantillas sean simples y de alguna manera familiares para cualquiera. ¡Probar!

editar este documento