W ostatnich latach Vue umacnia swoją pozycję w świecie frameworków frontendowych i jest elementem tak zwanego Big Three, czyli należy do trójki najczęściej używanych przez frontendowców narzędzi obok Reacta i Angulara do tworzenia aplikacji internetowych. Jako jedyny z wyżej wymienionych nie jest produktem wielkiej korporacji, a stoi za nim Evan You i jest rozwijany jako projekt open-source.
Najnowsza wersja oznaczona numerem 3 wprowadza wiele poprawek i zmian względem wcześniejszej wersji m.in. cały framework został przepisany z użyciem Typescripta, co pozwala na dużo łatwiejsze jego wykorzystanie w projektach, a inną dużą zmianą jest wprowadzenie Composition API, które jest tematem tego wpisu.
Dlaczego Composition API?
Composition API celuje w zwiększenie reużywalności kodu/komponentów i czytelności kodu, ponieważ praktycznie cały kod znajduje się w jednym miejscu poprzez zastąpienie różnych opcji (data, methods itd.) komponentu metodą setup (). Reużywalność zapewniona jest poprzez możliwość wyekstrahowania logiki z komponentu i wstrzykiwania do dowolnego komponentu, w którym chcemy z niej skorzystać, są to tzw. composition functions.
Poniżej przedstawiam małe porównanie.
Jak widzimy na przykładach, Composition API pozwala nam zawrzeć całą logikę w jednym miejscu. Do utworzenia reaktywnych zmiennych z prymitywnymi typami danych potrzebujemy użyć funkcji ref do owrapowania wartości i jak widzimy w funkcji doIt, dostęp mamy odwołując się do parametru value zmiennej. Wszystkie hooki są teraz wywoływane wewnątrz metody setup, a sama metoda setup zastępuje hook created, beforeCreate.
Kolejną ważną różnicą w porównaniu z Options API jest brak dostępu do `this` w metodzie setup. Jak w takim razie uzyskać dostęp do obiektu props zawierającego bindowane do komponentu dane?
Metoda setup przyjmuje dwa parametry: props i context. Wszystkie zbindowane właściwości mamy dostępne poprzez obiekt props. Ważnym jest, że nie możemy zdestrukturyzować argumentu props, ponieważ utracimy wtedy reaktywność. Zamiast tego musimy użyć funkcji toRefs, która pozwoli nam wypakować właściwości nie tracąc reaktywności.
Argument context możemy normalnie destrukturyzować i wyciągnąć z niego obiekty/funkcje: attrs, slots, emit i expose. Metoda setup zwraca wszystkie zmienne i funkcje, które chcemy wykorzystać w template.
Composition Function
W celu wyciągnięcia logiki z komponentów używamy composition functions. Pozwalają one nam na wyciągnięcie reaktywnego stanu oraz funkcjonalności poza komponent i używanie ich w dowolnym miejscu aplikacji. Z racji posiadania własnego stanu niezależnego od komponentów, w którym są używane, mogą w pewnym stopniu zastąpić Vuexa. Są odpowiednikami mixinów używanych w Options API. Korzystając z Composition API, projektowanie stron internetowych Wrocław staje się bardziej elastyczne, a komponenty bardziej reużywalne.
W komponentach dokonujemy destrukturyzacji na obiekcie zwracanym przez funkcje i wyciągamy interesujące nas dane i funkcje. Dzięki destrukturyzacji omijamy konflikty nazw właściwości, które pobieramy. Zwracane właściwości możemy stworzyć jako read-only i w ten sposób zapobiec ich mutacji bezpośrednio zmieniając ich wartość. Wtedy możemy wdrożyć taką samą zasadę działania jak w przypadku mutacji w Vuexie.
Zazwyczaj każda destrukturyzowana właściwość posiada swój lokalny stan w obrębie komponentu, ale nie ma przeszkód, żeby zdefiniować ją z globalnym stanem, który będzie dzielony przez komponenty ją używające. Przykładem może być pobrana z API lista osób, której stan powinien być dzielony przez wszystkie komponenty.
W przykładzie poniżej wyciągamy metodę zwracającą osoby. Następnie listę zwróconą przez funkcję getPersons podajemy w parametrze do funkcji reactive, która tworzy reaktywną kopię listy. Kopia jest deep tzn. że tworzymy również kopie wszystkich zagnieżdżonych referencyjnych typów danych.
Poniżej przedstawiam przykład funkcji, która zwraca globalny stan obiektu persons, więc będzie on dzielony przez wszystkie komponenty. Dodatkowo zwraca funkcje getPersons, która zwraca kopię persons tylko do odczytu i nie jest reaktywna, ale nic nie stoi na przeszkodzie, żeby w komponencie podać kopię, którą zwraca, jako argument funkcji reactive i uzyskamy reaktywną lokalną kopię. Funkcja getPerson pozwala nam po indeksie wyciągnąć z listy obiekt i zwraca jej właściwości, które są reaktywne (jak po użyciu ref). Ich zmiana w komponencie będzie globalna dla obiektu znajdującego się w liście. Funkcja addPerson z kolei pozwala nam na mutację listy poprzez dodanie kolejnego elementu.
Przykład użycia w komponencie.
I wynik console.loga.
Jak widać, zmiana zdestrukturyzowanej właściwości pierwszego obiektu na liście ma globalny wpływ na listę, jak i również dodanie kolejnego obiektu do listy.
Podsumowanie
Powyżej przedstawiłem minimalne przykłady pracy z Composition API w Vue 3. Moim zdaniem jest to duże usprawnienie względem Options API pozwalające na zwiększenie reużywalności kodu. To co zaprezentowałem w tym wpisie to tylko wierzchołek góry lodowej, a Vue 3 oferuje jeszcze sporo przydatnych zmian względem poprzednika, które będę starał się zaprezentować w przyszłych wpisach.