Vuejs

Tutorial Vuejs: Componentes con Composition API

Vue: Aprende a usar la Composition API para organizar y reutilizar lógica en componentes. Mejora tu código Vue con funciones de setup, reactividad y composables.

¿Qué es la Composition API?

La Composition API es una nueva forma de organizar y reutilizar la lógica en los componentes de Vue 3.X. 

A diferencia de la Options API, que estructura los componentes en secciones específicas como data, methods, computed, etc., la Composition API permite agrupar la lógica relacionada en funciones reutilizables. Esto no solo mejora la legibilidad y mantenibilidad del código, sino que también facilita la reutilización de la lógica entre diferentes componentes.

La Composition API se basa principalmente en el uso de funciones de setup y hooks reactivas. La función setup es el punto de entrada de un componente cuando se utiliza la Composition API. Aquí es donde se inicializa la lógica del componente. 

Dentro de setup, puedes definir variables reactivas, métodos y propiedades computadas, y organizarlas de manera más modular.

Ejemplo básico de la función setup:

import { ref } from 'vue';

export default {
  setup() {
    const count = ref(0);

    function increment() {
      count.value++;
    }

    return {
      count,
      increment
    };
  }
};

En este ejemplo, ref se utiliza para declarar una variable reactiva llamada count. La función increment se define para incrementar el valor de count. Ambas se retornan desde setup y están disponibles para ser utilizadas en el template del componente.

Otra forma de utilizar setup sería:

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

  const count = ref(0);

  function increment() {
    count.value++;
  }
</script>

La Composition API también introduce la capacidad de crear composables, que son funciones reutilizables que encapsulan lógica relacionada. Por ejemplo, puedes crear un composable para gestionar el estado de autenticación de un usuario:

import { ref } from 'vue';

export function useAuth() {
  const isAuthenticated = ref(false);

  function login() {
    isAuthenticated.value = true;
  }

  function logout() {
    isAuthenticated.value = false;
  }

  return {
    isAuthenticated,
    login,
    logout
  };
}

Este composable useAuth puede ser importado y utilizado en cualquier componente, promoviendo la reutilización de código:

import { useAuth } from './useAuth';

export default {
  setup() {
    const { isAuthenticated, login, logout } = useAuth();

    return {
      isAuthenticated,
      login,
      logout
    };
  }
};

La Composition API no reemplaza a la Options API; ambas coexisten y puedes elegir cuál usar dependiendo de tus necesidades. No obstante, la Composition API es especialmente útil para proyectos grandes y complejos donde la organización y la reutilización de la lógica son cruciales.

Estructura básica de un componente con Composition API

En Vue, la Composition API introduce una manera modular y flexible de estructurar los componentes. 

La clave de esta API es la función setup, que se ejecuta antes de que el componente sea creado y es el lugar donde se define toda la lógica del componente. La estructura básica de un componente utilizando la Composition API es la siguiente:

  1. Importación de funciones y utilidades desde Vue.
  2. Definición de la función setup.
  3. Declaración de variables reactivas.
  4. Definición de métodos y propiedades computadas.
  5. Retorno de las propiedades y métodos que se utilizarán en el template.

Ejemplo de estructura básica de un componente con Composition API:

import { ref, computed } from 'vue';

export default {
  name: 'MiComponente',
  setup() {
    // Declaración de variables reactivas
    const mensaje = ref('Hola, Vue');
    const contador = ref(0);

    // Propiedad computada
    const mensajeEnMayusculas = computed(() => mensaje.value.toUpperCase());

    // Método
    function incrementarContador() {
      contador.value++;
    }

    // Retorno de propiedades y métodos para el template
    return {
      mensaje,
      contador,
      mensajeEnMayusculas,
      incrementarContador
    };
  }
};

En este ejemplo, ref se utiliza para crear variables reactivas mensaje y contador. Las propiedades reactivas son esenciales para que Vue pueda detectar y reaccionar a los cambios. La propiedad computada mensajeEnMayusculas se define utilizando computed, que permite derivar un valor basado en otras propiedades reactivas.

La función incrementarContador es un método que modifica el estado de contador. En la función setup, se retorna un objeto que contiene las propiedades y métodos que queremos hacer accesibles en el template del componente. Este objeto se puede utilizar directamente en el template para enlazar datos y eventos.

El template de este componente podría ser:

<template>
  <div>
    <p>{{ mensaje }}</p>
    <p>{{ mensajeEnMayusculas }}</p>
    <button @click="incrementarContador">Incrementar</button>
    <p>Contador: {{ contador }}</p>
  </div>
</template>

En este template, {{ mensaje }}, {{ mensajeEnMayusculas }} y {{ contador }} muestran los valores de las propiedades reactivas y computadas. El evento @click en el botón llama al método incrementarContador, que incrementa el valor de contador.

Es importante recordar que la Composition API permite una mayor flexibilidad y organización al agrupar la lógica relacionada dentro de la función setup. Esto facilita la reutilización de la lógica entre diferentes componentes y mejora la mantenibilidad del código en aplicaciones complejas.

Uso de reactividad con ref y reactive

En Vue, la reactividad es uno de los conceptos fundamentales, y la Composition API introduce dos funciones clave para manejarla: ref y reactive. Ambas permiten crear variables reactivas, pero se utilizan en contextos ligeramente diferentes y tienen comportamientos específicos.

ref se utiliza para crear una referencia reactiva a un valor primitivo o a un objeto. La reactividad se maneja a través de la propiedad .value. Es especialmente útil cuando necesitas una referencia reactiva a un valor simple como un número, un string o un booleano.

Ejemplo de uso de ref:

import { ref } from 'vue';

export default {
  setup() {
    const count = ref(0);
    const message = ref('Hola, Vue');

    function increment() {
      count.value++;
    }

    return {
      count,
      message,
      increment
    };
  }
};

En este ejemplo, count y message son referencias reactivas. Para acceder o modificar su valor, se utiliza la propiedad .value.

Por otro lado, reactive se utiliza para crear un objeto reactivo. Al contrario que ref, no necesita la propiedad .value para acceder a las propiedades del objeto. Es más adecuado cuando se trabaja con objetos complejos que contienen múltiples propiedades.

Ejemplo de uso de reactive:

import { reactive } from 'vue';

export default {
  setup() {
    const state = reactive({
      count: 0,
      message: 'Hola, Vue'
    });

    function increment() {
      state.count++;
    }

    return {
      state,
      increment
    };
  }
};

En este caso, state es un objeto reactivo y puedes acceder directamente a sus propiedades sin usar .value.

Ambas funciones ref y reactive pueden combinarse para manejar estados más complejos. Por ejemplo, podrías tener un objeto reactivo con algunas propiedades que son referencias reactivas.

Ejemplo combinado de ref y reactive:

import { ref, reactive } from 'vue';

export default {
  setup() {
    const state = reactive({
      count: ref(0),
      message: 'Hola, Vue',
      user: {
        name: ref('Juan'),
        age: ref(30)
      }
    });

    function increment() {
      state.count.value++;
    }

    function updateUserName(newName) {
      state.user.name.value = newName;
    }

    return {
      state,
      increment,
      updateUserName
    };
  }
};

En este ejemplo, state es un objeto reactivo que incluye referencias reactivas dentro de sus propiedades. Esto permite un control fino sobre la reactividad de cada propiedad individual.

Es importante tener en cuenta que, aunque reactive puede envolver objetos complejos, no puede envolver valores primitivos directamente. Si intentas hacer reactive(0), Vue no podrá hacer que el valor sea reactivo. Para valores primitivos, siempre debes usar ref.

El uso adecuado de ref y reactive permite una gestión eficiente del estado en los componentes de Vue, facilitando la creación de aplicaciones más mantenibles y organizadas.

Propiedades computed

Las propiedades computed en Vue son una herramienta esencial para derivar valores basados en otras propiedades reactivas, sin necesidad de recalcular manualmente esos valores cada vez que cambian las dependencias. Con la Composition API, las propiedades computed se declaran utilizando la función computed importada desde el paquete Vue.

Las propiedades computed son ideales para situaciones donde necesitas realizar cálculos o transformaciones sobre datos reactivos y quieres que estos se actualicen automáticamente cuando los datos de origen cambian. A diferencia de los métodos, las propiedades computed están optimizadas para el rendimiento, ya que Vue almacena en caché sus resultados y solo recalcula cuando sus dependencias cambian.

Para declarar una propiedad computed en un componente usando la Composition API, sigue estos pasos:

  1. Importa la función computed desde Vue.
  2. Define la propiedad computed dentro de la función setup.
  3. Retorna la propiedad computed desde setup para que esté disponible en el template del componente.

Ejemplo básico de uso de propiedades computed:

import { ref, computed } from 'vue';

export default {
  setup() {
    const mensaje = ref('Hola, Vue');
    const contador = ref(0);

    const mensajeEnMayusculas = computed(() => mensaje.value.toUpperCase());

    const contadorDoble = computed(() => contador.value * 2);

    return {
      mensaje,
      contador,
      mensajeEnMayusculas,
      contadorDoble
    };
  }
};

En este ejemplo, mensajeEnMayusculas y contadorDoble son propiedades computed. mensajeEnMayusculas convierte el valor de mensaje a mayúsculas, mientras que contadorDoble multiplica el valor de contador por dos. Ambas propiedades se recalculan automáticamente cuando cambian sus dependencias (mensaje y contador respectivamente).

Las propiedades computed también pueden tener un getter y un setter, permitiendo una mayor flexibilidad. El getter define cómo se calcula el valor de la propiedad, mientras que el setter define cómo se actualiza el valor cuando se establece desde el exterior.

Ejemplo de propiedad computed con getter y setter:

import { ref, computed } from 'vue';

export default {
  setup() {
    const nombre = ref('Juan');
    
    const nombreCompleto = computed({
      get: () => `${nombre.value} Pérez`,
      set: (nuevoNombreCompleto) => {
        const partes = nuevoNombreCompleto.split(' ');
        if (partes.length > 1) {
          nombre.value = partes[0];
        }
      }
    });

    return {
      nombre,
      nombreCompleto
    };
  }
};

En este ejemplo, nombreCompleto tiene un getter que concatena el valor de nombre con el apellido "Pérez". El setter permite actualizar el valor de nombre cuando se establece un nuevo valor para nombreCompleto.

El uso de propiedades computed en la Composition API permite una mayor modularidad y claridad en el manejo de la lógica derivada dentro de los componentes de Vue, facilitando la creación de aplicaciones complejas y mantenibles.

Observadores con watch y watchEffect

En Vue, la Composition API introduce los métodos watch y watchEffect para observar y reaccionar a los cambios en las propiedades reactivas. Ambos métodos son útiles cuando necesitas ejecutar efectos secundarios en respuesta a cambios en los datos.

watch permite observar propiedades reactivas específicas y ejecutar una función de devolución de llamada cuando estas propiedades cambian. Este método es flexible y permite múltiples opciones de configuración. Es especialmente útil para realizar tareas asíncronas o cuando necesitas un control más detallado sobre los cambios.

Ejemplo básico de watch:

import { ref, watch } from 'vue';

export default {
  setup() {
    const mensaje = ref('Hola, Vue');
    const contador = ref(0);

    watch(mensaje, (nuevoValor, valorAntiguo) => {
      console.log(`El mensaje cambió de "${valorAntiguo}" a "${nuevoValor}"`);
    });

    watch(contador, (nuevoValor, valorAntiguo) => {
      console.log(`El contador cambió de ${valorAntiguo} a ${nuevoValor}`);
    });

    function incrementarContador() {
      contador.value++;
    }

    return {
      mensaje,
      contador,
      incrementarContador
    };
  }
};

En este ejemplo, watch está observando las propiedades mensaje y contador. La función de devolución de llamada se ejecuta cada vez que una de estas propiedades cambia, proporcionando el nuevo valor y el valor antiguo.

watchEffect, por otro lado, es una función más simple y reactiva que se ejecuta inmediatamente y rastrea automáticamente las dependencias reactivas utilizadas dentro de su función de devolución de llamada. Cada vez que cualquiera de estas dependencias cambia, la función se vuelve a ejecutar. No requiere especificar explícitamente las propiedades a observar, lo que lo hace más fácil de usar en muchos casos.

Ejemplo básico de watchEffect:

import { ref, watchEffect } from 'vue';

export default {
  setup() {
    const mensaje = ref('Hola, Vue');
    const contador = ref(0);

    watchEffect(() => {
      console.log(`El mensaje es: ${mensaje.value}`);
    });

    watchEffect(() => {
      console.log(`El contador es: ${contador.value}`);
    });

    function incrementarContador() {
      contador.value++;
    }

    return {
      mensaje,
      contador,
      incrementarContador
    };
  }
};

En este ejemplo, watchEffect rastrea automáticamente las dependencias mensaje y contador. Cada vez que cualquiera de estas propiedades cambia, las respectivas funciones de devolución de llamada se ejecutan nuevamente.

watch y watchEffect también permiten opciones avanzadas. Por ejemplo, puedes usar watch con una opción immediate para ejecutar la devolución de llamada inmediatamente en la primera renderización:

watch(mensaje, (nuevoValor, valorAntiguo) => {
  console.log(`El mensaje cambió de "${valorAntiguo}" a "${nuevoValor}"`);
}, { immediate: true });

Además, watch puede observar múltiples propiedades reactivas combinadas utilizando una matriz:

watch([mensaje, contador], ([nuevoMensaje, nuevoContador], [mensajeAntiguo, contadorAntiguo]) => {
  console.log(`El mensaje cambió de "${mensajeAntiguo}" a "${nuevoMensaje}" y el contador de ${contadorAntiguo} a ${nuevoContador}`);
});

Para watchEffect, puedes controlar cuándo limpiar los efectos secundarios utilizando un retorno de función dentro de la función de devolución de llamada:

watchEffect((onCleanup) => {
  const id = setInterval(() => {
    console.log(`El contador es: ${contador.value}`);
  }, 1000);

  onCleanup(() => {
    clearInterval(id);
  });
});

En este ejemplo, onCleanup se utiliza para limpiar el intervalo cuando el efecto se vuelve a ejecutar o se destruye el componente.

El uso de watch y watchEffect en la Composition API proporciona herramientas flexibles y potentes para gestionar efectos secundarios y reaccionar a los cambios en los datos, mejorando la reactividad y el control del estado en los componentes de Vue.

Certifícate en Vuejs con CertiDevs PLUS

Ejercicios de esta lección Componentes con Composition API

Evalúa tus conocimientos de esta lección Componentes con Composition API con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de Vuejs

Accede a todas las lecciones de Vuejs y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

En esta lección

Objetivos de aprendizaje de esta lección

  1. Comprender el propósito y los beneficios de la Composition API en Vue.
  2. Aprender a estructurar componentes utilizando la función setup.
  3. Manejar la reactividad con ref y reactive.
  4. Implementar propiedades computed para derivar datos reactivos.
  5. Utilizar watch y watchEffect para observar cambios en propiedades reactivas.
  6. Crear y usar composables para lógica reutilizable entre componentes.