Cómo reutilizar la lógica en Vue.js con Composables

Al programar, es importante estructurar su código base para poder reutilizarlo siempre que sea posible. La duplicación de código puede inflar la base del código y complicar la depuración, especialmente en aplicaciones más grandes.

Vue simplifica la reutilización de código mediante elementos componibles. Los elementos componibles son funciones que encapsulan la lógica y puedes reutilizarlas en tu proyecto para manejar funcionalidades similares.

¿Siempre fueron Composables?

Antes de que Vue 3 introdujera los componibles, podías usar mixins para capturar código y reutilizarlo en diferentes partes de tu aplicación. Mixins contenía opciones de Vue.js, como datos, métodos y enlaces de ciclo de vida, lo que permitía la reutilización de código en múltiples componentes.

Para crear mixins, los estructura en archivos separados y luego los aplica a los componentes agregando el mixin a la propiedad mixins dentro del objeto de opciones del componente. Por ejemplo:

 
export const formValidationMixin = {
  data() {
    return {
      formData: {
        username: '',
        password: '',
      },
      formErrors: {
        username: '',
        password: '',
      },
    };
  },
  methods: {
    validateForm() {
      this.formErrors = {};
  
      if (!this.formData.username.trim()) {
        this.formErrors.username="Username is required.";
      }
  
      if (!this.formData.password.trim()) {
        this.formErrors.password = 'Password is required.';
      }
   
      return Object.keys(this.formErrors).length === 0;
    },
  },
};

Este fragmento de código muestra el contenido de un mixin para validar formularios. Este mixin alberga dos propiedades de datos (formData y formErrors) inicialmente configuradas con valores vacíos.

formData almacena datos de entrada para el formulario, incluidos los campos de nombre de usuario y contraseña inicializados como vacíos. formErrors refleja esta estructura para contener posibles mensajes de error, también inicialmente vacíos.

El mixin también contiene un método, validarForm(), para verificar que los campos de nombre de usuario y contraseña no estén vacíos. Si alguno de los campos está vacío, completa la propiedad de datos formErrors con un mensaje de error apropiado.

El método devuelve verdadero para un formulario válido, cuando formErrors está vacío. Puede usar el mixin importándolo a su componente Vue y agregándolo a la propiedad mixin del objeto Opciones:

 <template>
  <div>
    <form @submit.prevent="submitForm">
      <div>
        <label for="username">Username:</label>
        <input type="text" id="username" v-model="formData.username" />
        <span class="error">{{ formErrors.username }}</span>
      </div>

      <div>
        <label for="password">Password:</label>
        <input type="password" id="password" v-model="formData.password" />
        <span class="error">{{ formErrors.password }}</span>
      </div>

      <button type="submit">Submit</button>
    </form>
  </div>
</template>

<script>
import { formValidation } from "./formValidation.js";

export default {
  mixins: [formValidation],
  methods: {
    submitForm() {
      if (this.validateForm()) {
        alert("Form submitted successfully!");
      } else {
        alert("Please correct the errors in the form.");
      }
    },
  },
};
</script>

<style>
.error {
  color: red;
}
</style>

Este ejemplo muestra un componente de Vue escrito utilizando el enfoque de objeto Opciones. La propiedad mixins incluye todos los mixins que has importado. En este caso, el componente utiliza el método validarForm del mixin formValidation para informar al usuario si el envío del formulario se realizó correctamente.

Cómo utilizar componentes componibles

Un elemento componible es un archivo JavaScript autónomo con funciones adaptadas a inquietudes o requisitos específicos. Puede aprovechar la API de composición de Vue dentro de un elemento componible, utilizando funciones como referencias y referencias calculadas.

Este acceso a la API de composición le permite crear funciones que se integran en varios componentes. Estas funciones devuelven un objeto, que puede importar e incorporar fácilmente a los componentes de Vue a través de la función de configuración de la API de composición.

Cree un nuevo archivo JavaScript en el directorio src de su proyecto para usar un archivo componible. Para proyectos más grandes, considere organizar una carpeta dentro de src y crear archivos JavaScript separados para diferentes elementos componibles, asegurándose de que el nombre de cada elemento componible refleje su propósito.

Dentro del archivo JavaScript, defina la función que necesita. Aquí hay una reestructuración del mixin formValidation como componible:

 
import { reactive } from 'vue';

export function useFormValidation() {
  const state = reactive({
    formData: {
      username: '',
      password: '',
    },
    formErrors: {
      username: '',
      password: '',
    },
  });

  function validateForm() {
    state.formErrors = {};

    if (!state.formData.username.trim()) {
      state.formErrors.username="Username is required.";
    }

    if (!state.formData.password.trim()) {
      state.formErrors.password = 'Password is required.';
    }

    return Object.keys(state.formErrors).length === 0;
  }

  return {
    state,
    validateForm,
  };
}

Este fragmento comienza importando la función reactiva del paquete vue. Luego crea una función exportable, useFormValidation().

Continúa creando una variable reactiva, state, que alberga las propiedades formData y formErrors. Luego, el fragmento maneja la validación del formulario con un enfoque muy similar al mixin. Finalmente, devuelve la variable de estado y la función validarForm como un objeto.

Puede usar este elemento componible importando la función JavaScript desde el archivo en su componente:

 <template>
  <div>
    <form @submit.prevent="submitForm">
      <div>
        <label for="username">Username:</label>
        <input type="text" id="username" v-model="state.formData.username" />
        <span class="error">{{ state.formErrors.username }}</span>
      </div>

      <div>
        <label for="password">Password:</label>
        <input type="password" id="password" v-model="state.formData.password" />
        <span class="error">{{ state.formErrors.password }}</span>
      </div>

      <button type="submit">Submit</button>
    </form>
  </div>
</template>

<script setup>
import { useFormValidation } from "./formValidation.js";
import { ref } from "vue";
const { state, validateForm } = useFormValidation();

const submitForm = () => {
  if (validateForm()) {
    alert("Form submitted successfully!");
  } else {
    alert("Please correct the errors in the form.");
  }
};
</script>

<style>
.error {
  color: red;
}
</style>

Después de importar el elemento componible useFormValidation, este código desestructura el objeto JavaScript que devuelve y continúa con la validación del formulario. Alerta si el formulario enviado es exitoso o tiene errores.

Los composables son los nuevos mixins

Si bien los mixins eran útiles en Vue 2 para la reutilización de código, los componibles los han reemplazado en Vue 3. Los componibles proporcionan un enfoque más estructurado y fácil de mantener para reutilizar la lógica en aplicaciones Vue.js, lo que facilita la creación de aplicaciones web escalables con Vue.