Composition API en Vue 3: diferencias con Vue 2

vueJS
Etiquetas:

Ya hemos preparado una plantilla para trabajar con Vue usando Composition API, pero es indudable que sacar todo el provecho a Vue 3 requiere conocer las diferencias entre Vue 2 y Vue 3. O más bien, qué se ha aportado en Vue 3 que hace que merezca la pena subir de versión.

Salto de Vue 2 a Vue 3

Para comprender exactamente qué implica migrar a Vue 3, he realizado el curso From Vue 2 to Vue 3 que puedes encontrar en VueMastery.com. No es un curso muy largo, y te da una buena visión a los que ya tenemos experiencia con Vue 2 de cómo modificar tus hábitos para migrar.

Un clásico para el primer ejemplo: trabajando con Listas

Partiendo de nuestra plantilla, vamos a preparar un sencillo ejemplo cómo si trabajasemos con Vue 2, y posteriormente, realizaremos exactamente lo mismo usando Composition API. Con las diferencias que verás en el código ya puedes ir sacando algunas primeras conclusiones: lo aprendido en Vue 2 es perfectamente válido.

Evidentemente, seguir un camino u otro dependerá de lo que quieras conseguir y de tu destreza con Composition API.

El código HTML lo vamos a modificar un poquito, pero sólo para agregar un segundo DIV, de forma que podamos cargar en la misma página el código normal, y el composition API.

<!DOCTYPE html>
<html lang="es">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
    <title>Vue3 with @manejandodatos</title>
</head>

<body>
    <div id="app">    </div>
    <div id="app2">    </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script type="module" src="scripts/index.js"></script>
</body>
</html>

El código del módulo index.js

Index.js es el módulo de javascript que es donde arranca toda nuestra app. El código no varia mucho de la plantilla, pero ahora, incluimos cómo novedad la importación de 2 objetos procedente de nuestro componente app.js.

    import {tReactive, vue2} from '../components/app.js';

    const { createApp } = Vue;
    
    createApp(tReactive).mount('#app');
    createApp(vue2).mount('#app2');

Tal y cómo puedes observar, este fichero tampoco tiene complejidad y lo único que hacemos es montar cada uno de los objetos tReactive y Vue2 en un div distinto. Cómo podrás imaginar, el comportamiento de ambos DIVs será el mismo, porque lo que se pretende es ver las diferencias entre Vue 2 y Vue 3, con Composition API.

Addnew.js, para agregar nuevos datos

Antes de continuar, vamos a crear el fichero addnew.js, también en el mismo directorio components, y es simplemente un pequeño componente dónde se trabaja con el formulario para insertar nuevos datos a la lista.

El código es bastante sencillo, y se ha utilizado el estilo conocido de Vue 2 (ya tendremos tiempo de mejorarlo).

export default {
        name: 'addNew',
        data() {
            return {
                tarea:""
            }
        },
        methods: {
            enviar() {
                this.$emit('nuevo', this.tarea);
                this.tarea = "";
            }
        },
        template: `
        <form @submit.prevent="enviar">
            <input v-model.lazy="tarea" />
            <button type="submit">Add</button>
        </form>
        `
};

El código es perfectamente asimilable a los componentes de Vue2.

Entre los detalles que incluye, está incluir name, para darle un nombre al componente. Los datos reactivos son los incluidos en data y se ha preparado el método enviar, cuya finalidad es “emitir” un evento con el nuevo dato.

Cómo peculiaridad, y para evitar “recargar” todo, es importante el detalle de .prevent en el @submit del formulario. Y también, que se ha utilizado .lazy en el input para que todo se actualice cuando se pierda el foco.

El código de app.js usando Vue Composition API

Seguramente, algunas cosas se pueden reducir o hacer de otra manera, pero yo he creido conveniente utilizar algunas variables para evitar reescribir código que puede ser reutilizable. Empiezo por el código, y luego te comento los detalles:

import addNew from "./addnew.js";
const { reactive } = Vue;

const lists_def = ["uno", "dos"];
const template = `
<div>
  <h1>{{title}}</h1>
  <ul v-for="(i, index) in lists" key="index">
    <li>{{ i }}</li>
  </ul>
  <addNew @nuevo="nuevo"></addNew>
</div>
`;

const tReactive =  {
    name: 'tReactive',
    components: { addNew }, 
    setup() {
        const title = "List with Vue 3 Composition API";
        let lists = reactive([...lists_def]);        
        const nuevo = val => {
          lists.push(val);
          console.log(lists);
        }
        return { title, lists, nuevo };
    },
    template: template,
};

const vue2 = {
  components: { addNew  },
  data() {
    return {
      title: "List with Vue3",
      lists: [...lists_def],
    }
  },
  methods: {
    nuevo(val) { this.lists.push(val)  }
  },
  template: template,
}
export { tReactive, vue2} ;

Las importaciones de “cosas” se hace al principio, y aquí es donde importamos el formulario AddNew.js, que es un componente. Lo incluimos en las variables dentro de components: { addNew }. El motivo es simple: para decirle a Vue que queremos usar ese componente dentro de otro componente.

A continuación importamos reactive de Vue, que ya lo vimos en una entrada previa, para hacer reactiva las variables usando Composition API. Esto es importante, porque en caso de no utilizarlo, la variable sí se actualizará, pero NO se verá reflejado en el DOM. Y normalmente, cuando realizas una modificación, en “algo” se verá dicha modificación en el DOM.

A continuación definimos dos variables para no repetir código: una es list_def que es una lista de valores, y template, que es la que contiene nuestra plantilla y así la podemos utilizar con la variable de vue2 y de Composition API.

A continuación, definimos tReactive, que es lo que prepararemos con Composition API. Además del name, template y components, lo importante está en setup y en lo que devuelve (return).

En setup se define todo lo que teóricamente va en data (en vue2) y se incluyen además todo aquello que requiera la plantilla, como el método nuevo, que es una función.

Seguimos con la variable vue2, que es la definición de un componente de la forma más tradicional: definimos data, y en methods se incluye el código de nuevo.

La última línea es la que exporta las dos variables: tReactive y vue2, que básicamente hace lo mismo, pero de distinta forma.

Vue usando Composition API y al estilo de Vue 2

En la imagen anterior hemos agregado un elemento distinto a cada uno.

Primeras conclusiones de las diferencias entre Vue2 y Composition API

Dos caminos, llegando al mismo punto. Ninguno es mejor que otro, sólo que las reglas de uno y otro son distintas. Yo, de momento, estoy empezando a conocer Composition API, porque la otra forma ya me la conozco de Vue 2.

Sin lugar a duda, el hecho que puedas trabajar con las dos te permitirá utilizar la mejor forma en función del objetivo a conseguir, y evidentemente, de tu pericia cómo desarrollador.

Seguiremos trabajando en las próximas entregas del blog para mejorar el conocimiento de Composition API con más novedades.

El código completo del ejemplo lo tienes disponible en Github.

Y para terminar, este ejemplo tiene muchas mejoras, pero lo principal es que aprendas un poco las diferencias entre la programación clásica de Vue 2, compatible con la 3, y usar Composition API.

Personalmente, me ha servido mucho esta video sobre Vue 3:

Eso sí, yo he tardado más de esas 10 horas en ir descifrando todos los secretos de Vue 3.

Vuetify y Vue 3

Me hubiera gustado mucho crear una siguiente entrada con todo lo realizado en esta misma entrada, pero usando Vuetify. Sin embargo, en estos momentos (Diciembre 2020), Vuetify 2 no está soportado en Vue3.

Así que, no tenemos prisa en seguir aprendiendo poco a poco mientras llega Vuetify 3, o empiezan las primeras betas.

La única solución viable para usar Composition API con Vuetify es seguir utilizando la versión 2 de Vue, agregar el plugin Composition API, con las limitaciones que tiene, puesto que no es lo mismo (en algunas cosas)

Happy coding, y seguimos!