7 consejos de Vue3 que necesitas conocer

7 consejos de Vue3 que necesitas conocer

Publicado originalmente por Roland Doda - DEV Community

Hooks de VNode

En cada componente o etiqueta HTML, podemos usar algunos hooks especiales (no documentados) como escuchadores de eventos. Los hooks son:

  • onVnodeBeforeMount
  • onVnodeMounted
  • onVnodeBeforeUpdate
  • onVnodeUpdated
  • onVnodeBeforeUnmount
  • onVnodeUnmounted

Principalmente uso onVnodeMounted en componentes cuando necesito ejecutar código cuando el componente está montado u onVnodeUpdated para depurar cuando algo se actualiza pero estoy bastante seguro de que todos ellos pueden ser útiles en algunos casos.

Ejemplo:

<script setup>
    import { ref } from 'vue'

    const count = ref(0)

    function onMyComponentMounted() {}

    function divThatDisplaysCountWasUpdated() {}
</script>

<template>
    <MyComponent @vnodeMounted="onMyComponentMounted" />
    <div @vnodeUpdated="divThatDisplaysCountWasUpdated">{{ count }}</div>
</template>

Cabe señalar que estos hooks pasan algunos argumentos a la función de devolución de llamada. Pasan solo un argumento que es el VNode actual excepto para onVnodeBeforeUpdate y onVnodeUpdated que pasan dos argumentos, el VNode actual y el VNode anterior.

Hooks de depuración

Todos conocemos los hooks del ciclo de vida que Vue nos proporciona. ¿Pero sabías que Vue 3 nos proporciona dos hooks que podemos usar para propósitos de depuración? Son:

onRenderTracked se llama para cada dependencia reactiva que ha sido rastreada.

<script setup>
import { ref, onRenderTracked } from 'vue'

const count = ref(0)
const count2 = ref(0)

// Se llamará dos veces, una vez para count y otra para count2
onRenderTracked((event) => {
    console.log(event)
})
</script>

onRenderTriggered se llama cuando activamos una actualización de reactividad, o como dice la documentación: “cuando una dependencia reactiva activa el efecto de renderizado del componente para que se vuelva a ejecutar”.

<script setup>
import { ref, onRenderTriggered } from 'vue'

const count = ref(0)

// Se llamará cuando actualicemos count
onRenderTriggered((event) => {
    debugger
})
</script>

Exponer slots de un componente hijo

Si usas un componente de terceros, es probable que envuelvas su implementación en tu propio componente “envoltorio”. Esta es una buena práctica y una solución escalable, pero de esa manera, los slots de ese componente de terceros se pierden y debemos encontrar una forma de exponerlos al componente padre:

WrapperComponent.vue

<template>
  <div class="wrapper-of-third-party-component">
    <ThirdPartyComponent v-bind="$attrs">

        <!-- Exponer los slots del componente de terceros -->
        <template v-for="(_, name) in $slots" #[name]="slotData">
            <slot :name="name" v-bind="slotData || {}"></slot>
        </template>

    </ThirdPartyComponent>
  </div>
</template>

Ahora cada componente que use WrapperComponent puede usar los slots de ThirdPartyComponent :tada:.

Los estilos con scope y los nodos múltiples no funcionan bien juntos

En Vue 3 finalmente podemos tener componentes con más de “un nodo raíz”. Eso es genial, pero personalmente me encuentro con una limitación de diseño al hacerlo. Imagina que tenemos un componente hijo:

<template>
  <p class="my-p">First p</p>
  <p class="my-p">Second p</p>
</template>

Y un componente padre:

<template>
    <h1>My awesome component</h1>
    <MyChildComponent />
</template>

<style scoped>
// No hay forma de estilizar las etiquetas p de MyChildComponent
.my-p { color: red; }
:deep(.my-p) { color: red; }
</style>

No hay forma desde el estilo con scope del componente padre de múltiples raíces de estilizar las etiquetas p del componente hijo.

En resumen, un componente de múltiples raíces no puede dirigirse a los estilos de un componente hijo de múltiples raíces con estilos con scope.

La mejor forma de arreglarlo sería envolver el componente padre o hijo (o ambos) para que tengamos solo un elemento raíz.

Pero si absolutamente necesitas que ambos tengan nodos múltiples, puedes:

  • Usar un estilo sin scope
<style>
.my-p { color: red; }
</style>
  • Usar CSS Modules
<template>
    <h1>My awesome component</h1>
    <MyChildComponent :class="$style.trick" />
</template>

<style module>
.trick {
    color: red;
}
</style>

Como estamos especificando una clase aquí, el componente hijo de múltiples raíces debe especificar explícitamente el comportamiento de transferencia de atributos.

Si quieres mi opinión, a menos que absolutamente necesites un componente de nodo múltiple, ve con un nodo raíz único y no te ocupes de esta limitación de diseño en absoluto.

Ten cuidado al usar selectores CSS

#main-nav > li {} será muchas veces más lento comparado con .my-li { color: red }. De la documentación:

Debido a la forma en que los navegadores renderizan varios selectores CSS, p { color: red } será muchas veces más lento cuando tiene scope (es decir, cuando se combina con un selector de atributo). Si usas clases o ids en su lugar, como en .example { color: red }, entonces prácticamente eliminas ese impacto en el rendimiento.

Te recomiendo altamente que leas Efficiently Rendering CSS si quieres profundizar en este tema.

Conversión booleana

En Vue 2 o versiones anteriores de Vue 3, para props con tipos Boolean teníamos un comportamiento diferente dependiendo del orden:

1er caso:

props: {
  hoverColor: [String, Boolean] // <- por defecto ''
}

2do caso:

props: {
  hoverColor: [Boolean, String] // <- por defecto false
}

No solo eso, sino que si pasas el prop así:

<my-component hover-color></my-component>

En el primer caso, sería una cadena vacía ''. En el segundo caso, sería true.

Como puedes ver, esto era un poco confuso e inconsistente. Afortunadamente, en Vue 3, tenemos un nuevo comportamiento que es consistente y predecible:

El comportamiento de Boolean se aplicará independientemente del orden de aparición del tipo.

Entonces:

hoverColor: [String, Boolean] // <- por defecto false
hoverColor: [Boolean, String] // <- por defecto false
hoverColor: [Boolean, Number] // <- por defecto false

Template refs con v-for - El orden no está garantizado

recuerda este para que no pierdas horas depurando intentando averiguar qué está pasando

En el código siguiente:

<script setup>
import { ref } from "vue";

const list = ref([1, 2, 3]);
const itemRefs = ref([]);
</script>

<template>
  <ul>
    <li v-for="item in list" ref="itemRefs" :key="item">
      {{ item }}
    </li>
  </ul>
</template>

estamos iterando sobre el array list, y creamos el array itemRefs.

**itemRefsno se garantiza que tenga el mismo orden que el array list.

Si quieres saber más sobre esto, puedes leer este issue.

Finalizando el artículo

Tengo más consejos y trucos, pero este artículo ya se ha hecho largo. Espera otro artículo en el futuro cercano con consejos/trucos aún mejores.

¡Gracias a todos por leer, cualquier comentario es muy apreciado!

¿Conoces una empresa genial que está contratando desarrolladores de Vue.js?

Además, estoy buscando un nuevo trabajo, así que si conoces una empresa genial que está contratando un desarrollador Senior de Vue.js, por favor ponte en contacto conmigo en rolanddoda2014@gmail.com :folded_hands:.



Buy Me A Coffee