Jak znovu použít logiku ve Vue.js s Composables

V programování je klíčové vytvářet kód s důrazem na jeho opakované použití. Duplikace kódu vede k jeho zbytečnému nabobtnání a komplikuje následné ladění, zejména u rozsáhlých aplikací.

Vue usnadňuje opětovné využití kódu prostřednictvím takzvaných composables. Jedná se o funkce, které zapouzdřují specifickou logiku a umožňují její opakované použití v celém projektu pro různé, ale podobné funkce.

Byla možnost composables vždy k dispozici?

Před příchodem Vue 3 s jeho composables bylo možné k zachycení a opakovanému využití kódu v různých částech aplikace používat mixiny. Mixiny obsahovaly Vue.js vlastnosti, jako jsou data, metody a životní cykly, což umožňovalo opětovné použití kódu v rámci několika komponent.

Pro vytvoření mixinu bylo nutné ho strukturovat do samostatného souboru a poté ho aplikovat na komponenty přidáním mixinu do vlastnosti `mixins` v konfiguračním objektu komponenty. Příklad:

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;
    },
  },
};

Tento úsek kódu demonstruje mixin pro ověřování formulářů. Obsahuje dvě datové vlastnosti – `formData` a `formErrors` – inicializované prázdnými hodnotami.

`formData` slouží k uložení vstupních dat formuláře, včetně uživatelského jména a hesla, které jsou na začátku prázdné. `formErrors` zrcadlí tuto strukturu a je určeno pro ukládání případných chybových hlášení, rovněž inicializované jako prázdné.

Mixiny také definují metodu `validateForm()`, která kontroluje, zda pole pro uživatelské jméno a heslo nejsou prázdná. Pokud je některé z polí prázdné, uloží do vlastnosti `formErrors` příslušnou chybovou zprávu.

Metoda vrací `true` pro platný formulář, když je `formErrors` prázdný. Mixin se používá importem do komponenty Vue a přidáním do vlastnosti `mixin` objektu `Options`:

<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>

Tento příklad ukazuje komponentu Vue vytvořenou s použitím objektového přístupu `Options`. Vlastnost `mixins` zahrnuje všechny importované mixiny. V tomto případě komponenta využívá metodu `validateForm` z mixinu `formValidation` k informování uživatele o úspěšném či neúspěšném odeslání formuláře.

Jak se používají Composables

Composable je samostatný JavaScriptový soubor s funkcemi specializovanými na konkrétní úlohy nebo požadavky. V rámci composables lze využít Composition API Vue s funkcemi jako `ref` a `computed`.

Tento přístup umožňuje vytvářet funkce, které se integrují do různých komponent. Tyto funkce vracejí objekt, který lze jednoduše importovat a začlenit do komponent Vue prostřednictvím funkce `setup` Composition API.

Pro použití composables je nutné vytvořit nový JavaScriptový soubor v adresáři `src` projektu. U rozsáhlejších projektů se doporučuje organizovat soubory v rámci složky a vytvářet samostatné soubory pro různé composables, přičemž je vhodné pojmenovat soubory podle jejich účelu.

V JavaScriptovém souboru se definuje požadovaná funkce. Následuje restrukturalizace mixinu `formValidation` do composable:

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,
  };
}

Kód začíná importem reaktivní funkce z balíčku `vue`. Následuje vytvoření exportovatelné funkce `useFormValidation()`.

Dále se vytvoří reaktivní proměnná `state`, která obsahuje vlastnosti `formData` a `formErrors`. Poté kód zpracovává validaci formuláře obdobným způsobem jako mixin. Nakonec vrací proměnnou `state` a funkci `validateForm` jako objekt.

Toto composable je možné použít importováním JavaScriptové funkce ze souboru v komponentě:

<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>

Po importování composable `useFormValidation` kód destrukturuje JavaScriptový objekt, který funkce vrací, a pokračuje v ověřování formuláře. Informuje uživatele, zda bylo odeslání formuláře úspěšné, nebo zda obsahuje chyby.

Composables jsou nové mixiny

Zatímco mixiny byly užitečné ve Vue 2 pro opakované použití kódu, composables je nahradily ve Vue 3. Composables poskytují strukturovanější a lépe udržovatelný přístup k opakovanému využití logiky v aplikacích Vue.js, což usnadňuje vytváření škálovatelných webových aplikací pomocí Vue.