Uso avanzado de Composables

Avanzado
Vuejs
Vuejs
Actualizado: 17/09/2024

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

Composición y encadenamiento de composables

En Vue, los composables son funciones reutilizables que encapsulan lógica reactiva. La composición de composables permite combinar múltiples composables y crear abstracciones más complejas. El encadenamiento de composables se refiere a la práctica de utilizar la salida de un composable como entrada de otro, lo que permite una orquestación fluida de la lógica.

Para ilustrar la composición, considere un composable que maneja el estado de autenticación de un usuario:

// useAuth.js
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 };
}

Ahora, imagine que desea crear un nuevo composable que también maneje la autorización basada en roles. Puede componer este nuevo composable utilizando useAuth:

// useRole.js
import { ref } from 'vue';
import { useAuth } from './useAuth';

export function useRole() {
    const role = ref("invitado")

    function changeRoleToAdmin() {
        role.value = "admin";
    }

    return { useAuth, role, changeRoleToAdmin };
}

En este ejemplo, useAuthorization utiliza useAuth para determinar si un usuario está autenticado antes de verificar su rol. Esto demuestra cómo los composables pueden componerse para crear lógica más rica y compleja.

El encadenamiento de composables se puede observar cuando un composable depende de la salida de otro. Por ejemplo, si tiene un composable que maneja la configuración de la aplicación, puede encadenarlo con useAuthorization para condicionar la configuración según el rol del usuario:

<!-- App.vue -->
<template>
    <div ref="div" style="padding: 1em;">
        Tema para el usuario {{ userRole }}
    </div>

    <br>

    <button v-if="!isAuthenticated" @click="register()">Iniciar
        sesión</button>
    <button v-else type="button" @click="changeRoleToAdmin()">Cambiar rol a Admin</button>
    <button type="button" @click="signOut()">Cerrar sesión</button>
</template>

<script setup lang="ts">
  import { computed, ref, watch } from 'vue';
  import { useRole } from '../composables/useRole';

  const div = ref<HTMLElement>();

  const { useAuth, role, changeRoleToAdmin } = useRole();

  const { isAuthenticated, login, logout } = useAuth()

  const canAccessAdmin = computed(() => isAuthenticated.value && role.value === 'admin');
  const userRole = computed(() => role.value)

  function register() {
      login();
      role.value = 'registrado';
  }

  function signOut() {
      logout();
      role.value = 'invitado';
  }

  watch(canAccessAdmin, (newValue) => {
      console.log("el valor ha pasado de: ", canAccessAdmin, " a: ", newValue);
      if (newValue) {
          div.value!.style.background = "black"
          div.value!.style.color = "white"
      } else {
          div.value!.style.background = "white"
          div.value!.style.color = "black"
      }
  });
</script>

Aquí, se observa los cambios en canAccessAdmin de useAuthorization para ajustar la configuración de la aplicación. Este encadenamiento permite que la lógica de configuración reaccione automáticamente a los cambios en la autorización del usuario.

La práctica de componer y encadenar composables facilita la creación de aplicaciones modulares y mantenibles, permitiendo a los desarrolladores dividir la lógica en piezas manejables y reutilizables.

¿Te está gustando esta lección?

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

Inyección de dependencias en composables

En Vue, la inyección de dependencias en composables es una técnica que permite a los desarrolladores compartir y gestionar dependencias de manera eficiente a través de los diferentes niveles de la jerarquía de componentes. Esto se logra mediante el uso de las funciones provide y inject, que facilitan el paso de datos o funciones desde un proveedor hasta un consumidor sin necesidad de prop drilling.

Para implementar la inyección de dependencias en composables, primero se define un proveedor que utiliza provide para exponer una dependencia. Luego, en cualquier componente o composable descendiente, se utiliza inject para acceder a esa dependencia.

Ejemplo de uso básico de provide e inject en un composable:

// useThemeProvider.js
import { provide, ref } from 'vue';

export function useThemeProvider() {
  const theme = ref('light');
  
  provide('theme', theme);
  
  return { theme };
}

En este ejemplo, useThemeProvider es un composable que define un estado reactivo theme y lo proporciona a través del árbol de componentes. Cualquier componente descendiente puede inyectar este theme y reaccionar a sus cambios.

Para consumir esta dependencia en un composable o componente, se utiliza inject de la siguiente manera:

// useThemeConsumer.js
import { inject } from 'vue';

export function useThemeConsumer() {
  const theme = inject('theme', ref('defaultTheme'));
  
  return { theme };
}

Aquí, useThemeConsumer inyecta el theme proporcionado. En caso de que no haya un proveedor en la jerarquía, se utilizará el valor predeterminado defaultTheme.

La inyección de dependencias es especialmente útil en aplicaciones grandes o complejas, donde es necesario compartir configuraciones o servicios entre múltiples componentes sin crear dependencias fuertes. No obstante, se debe usar con cuidado para evitar la creación de dependencias ocultas que puedan dificultar la comprensión del flujo de datos en la aplicación.

En situaciones avanzadas, como la inyección de servicios o instancias de clases, se puede proporcionar e inyectar funciones o clases completas, lo que permite un alto grado de flexibilidad y modularidad. Aquí un ejemplo de cómo inyectar un servicio:

// loggerService.js
export class LoggerService {
  log(message: string) {
    console.log('Log:', message);
  }
}
// useLoggerProvider.js
import { provide } from 'vue';
import { LoggerService } from '../../services/loggerServices';

export function useLoggerProvider() {
  provide('logger', new LoggerService());
}
// useLoggerConsumer.js
import { inject } from 'vue';
import { LoggerService } from '../../services/loggerServices';

export function useLoggerConsumer() {
  const logger = inject<LoggerService>("logger", new LoggerService());
  
  function logMessage(message: string) {
    if (logger) {
      logger.log(message);
    }
  }
  
  return { logMessage };
}

En este caso, useLoggerProvider proporciona una instancia de LoggerService, y useLoggerConsumer inyecta y utiliza el servicio para registrar mensajes. Este enfoque permite mantener el código modular y reutilizable, facilitando la gestión de dependencias en aplicaciones Vue.

Creación de composables con async y await

En Vue, los composables son funciones reutilizables que encapsulan lógica reactiva y permiten estructurar el código de manera más modular. Al integrar async y await en composables, se puede gestionar de forma eficiente la lógica asíncrona, como llamadas a API, dentro de una aplicación Vue.

Para crear un composable que maneje operaciones asíncronas, es crucial definir la función del composable como async. Esto permite utilizar await dentro de la función para esperar la resolución de promesas antes de continuar con la ejecución. Aquí se muestra cómo definir un composable asíncrono:

// useFetchData.js
import { ref } from 'vue';

export async function useFetchData(url) {
  const data = ref(null);
  const error = ref(null);

  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    data.value = await response.json();
  } catch (err) {
    error.value = err.message;
  }

  return { data, error };
}

En este ejemplo, useFetchData es un composable que realiza una solicitud HTTP para obtener datos desde un url proporcionado. Utiliza await para esperar la respuesta de la función fetch y maneja errores potenciales mediante un bloque try-catch. Los valores de data y error se definen como referencias reactivas que pueden ser utilizadas en componentes para reaccionar a los cambios de estado.

Para utilizar este composable en un componente Vue, se puede hacer de la siguiente manera:

// DataDisplayComponent.vue
<template>
  <div>
    <div v-if="error">{{ error }}</div>
    <div v-else-if="data">
      <pre>{{ data }}</pre>
    </div>
    <div v-else>Cargando...</div>
  </div>
</template>

<script setup>
import { onMounted } from 'vue';
import { useFetchData } from './useFetchData.js';

const { data, error } = await useFetchData('https://api.example.com/data');

onMounted(() => {
  // Lógica adicional si es necesario al montar el componente
});
</script>

En este componente DataDisplayComponent.vue, se utiliza el composable useFetchData para obtener datos de una API. La llamada a useFetchData se realiza con await para asegurar que los datos se cargan antes de que el componente se monte completamente, y se gestiona el estado de carga con un simple condicional en la plantilla.

Es importante tener en cuenta que, aunque async y await hacen que el código asíncrono sea más fácil de leer y escribir, se debe gestionar adecuadamente el estado de carga y los errores para proporcionar una experiencia de usuario fluida. Además, debido a que las funciones de setup en componentes de composición no pueden ser asíncronas, cualquier lógica asíncrona debe manejarse dentro de funciones auxiliares o composables como se muestra en los ejemplos anteriores.

El uso de composables con async y await en Vue mejora la legibilidad del código y facilita la gestión de tareas asíncronas, manteniendo la reactividad y modularidad del código.

Aprendizajes de esta lección

  1. Componer y encadenar múltiples composables.
  2. Utilizar inyección de dependencias con provide e inject.
  3. Manejar operaciones asíncronas con async y await en composables.
  4. Implementar patrones avanzados de reutilización de lógica en Vue.

Completa Vuejs y certifícate

Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración