Jak ponownie wykorzystać logikę w Vue.js z elementami Composable

Photo of author

By maciekx

W procesie programowania kluczowe jest takie projektowanie struktury kodu, aby umożliwić jego efektywne ponowne użycie. Unikanie duplikacji kodu pozwala utrzymać projekt w porządku, a debugowanie staje się znacznie prostsze, zwłaszcza w rozbudowanych aplikacjach.

Framework Vue oferuje mechanizm upraszczający ponowne wykorzystanie fragmentów kodu, a mianowicie tzw. kompozyty. Są to funkcje, które w elegancki sposób enkapsulują określoną logikę i umożliwiają jej wykorzystanie w różnych miejscach projektu, wszędzie tam, gdzie zachodzi potrzeba realizacji podobnej funkcjonalności.

Czy od zawsze mieliśmy do dyspozycji kompozyty?

Przed wprowadzeniem kompozytów w Vue 3, do przechwytywania i ponownego wykorzystywania kodu w różnych częściach aplikacji stosowano tzw. miksy. Miksy zawierały różne elementy specyficzne dla Vue.js, takie jak dane, metody oraz hooki cyklu życia, dzięki czemu możliwe było współdzielenie logiki pomiędzy komponentami.

Aby skorzystać z miksów, należało zdefiniować je w osobnych plikach, a następnie dołączyć do konkretnych komponentów poprzez dodanie miksu do właściwości `mixins` w obiekcie opcji komponentu. Przykładowo:

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

Powyższy kod prezentuje przykładowy miks służący do walidacji formularzy. Definiuje on dwie właściwości danych: `formData` oraz `formErrors`, które początkowo są puste.

`formData` służy do przechowywania danych z formularza, w tym pól na nazwę użytkownika i hasło, zainicjalizowanych pustymi ciągami znaków. `formErrors` natomiast odzwierciedla strukturę `formData` i przechowuje ewentualne komunikaty o błędach, także z pustymi wartościami na początku.

Miks ten zawiera również metodę `validForm()`, która sprawdza, czy pola nazwy użytkownika i hasła nie są puste. Jeśli którekolwiek z pól jest puste, właściwość `formErrors` jest wypełniana odpowiednim komunikatem.

Metoda zwraca `true` jeśli formularz jest poprawny, czyli gdy obiekt `formErrors` jest pusty. Miks ten można wykorzystać w komponencie Vue poprzez importowanie go i dodanie do właściwości `mixin` obiektu opcji komponentu, w następujący sposób:

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

Powyższy przykład prezentuje komponent Vue, w którym zastosowano podejście oparte na obiekcie opcji. Właściwość `mixins` zawiera wszystkie importowane miksy. W tym konkretnym przypadku, komponent wykorzystuje metodę `validForm` z miksu `formValidation`, aby informować użytkownika, czy proces przesłania formularza zakończył się sukcesem.

Jak korzystać z kompozytów?

Plik z kompozytem to samodzielny plik JavaScript, który zawiera funkcje dostosowane do rozwiązywania konkretnych problemów lub wymagań. Kompozyt może wykorzystywać interfejs API kompozycji Vue, co oznacza używanie takich funkcji jak referencje (refs) i referencje obliczane (computed refs).

Dostęp do API kompozycji umożliwia tworzenie funkcji, które z łatwością można integrować z różnymi komponentami. Te funkcje zwracają obiekt, który można łatwo zaimportować i włączyć do komponentów Vue za pomocą funkcji `setup` interfejsu API kompozycji.

Aby użyć kompozytu, należy utworzyć nowy plik JavaScript w katalogu `src` swojego projektu. W przypadku bardziej rozbudowanych projektów warto rozważyć stworzenie oddzielnego folderu w katalogu `src` i umieszczenie w nim oddzielnych plików JavaScript dla każdego kompozytu. Należy zadbać, aby nazwa każdego kompozytu dobrze odzwierciedlała jego przeznaczenie.

W pliku JavaScript zdefiniuj potrzebną funkcję. Poniżej znajduje się przykład, jak przekształcić `formValidation` miks w kompozyt:

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

Powyższy kod rozpoczyna się od zaimportowania funkcji `reactive` z pakietu `vue`. Następnie tworzona jest eksportowana funkcja `useFormValidation()`.

Kolejnym krokiem jest utworzenie reaktywnej zmiennej `state`, która zawiera właściwości `formData` i `formErrors`. Następnie w kodzie znajduje się implementacja walidacji formularza, która jest bardzo zbliżona do tej znanej z miksów. Na końcu, zwracana jest zmienna `state` oraz funkcja `validForm` w postaci obiektu.

Komponent ten może zostać wykorzystany poprzez zaimportowanie funkcji JavaScript z pliku do komponentu, w następujący sposób:

 <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 zaimportowaniu kompozytu `useFormValidation` powyższy kod destrukturyzuje zwracany obiekt JavaScript, a następnie przystępuje do walidacji formularza. Na koniec, wyświetla komunikat informujący, czy proces przesyłania formularza zakończył się sukcesem, czy też wystąpiły błędy.

Kompozyty to nowa generacja miksów

Chociaż miksy w Vue 2 były użyteczne do ponownego wykorzystywania kodu, w Vue 3 zostały zastąpione przez komponenty kompozycyjne. Kompozyty zapewniają bardziej zorganizowane i łatwiejsze w utrzymaniu podejście do ponownego wykorzystania logiki w aplikacjach Vue.js, ułatwiając tym samym tworzenie skalowalnych aplikacji internetowych z użyciem frameworka Vue.


newsblog.pl