Reaktywność w Vue, czyli reagowanie na zmiany stanu komponentów jest stosunkowo prosta i nie wymaga głębszych analiz. Niestety zdarzają się wyjątki i nie inaczej jest w tym wypadku, że rwiemy włosy z głowy szukając przyczyny rozwiązania problemu, gdzie wszystko jest niby oczywiste. W tym artykule omawiam nieco dokładniej reaktywność w Vue i pewien skrajny przypadek, o którym warto pamiętać.
Na początek załóżmy, że do obiektu umieszczonego w data
chcemy dodać kolejny obiekt w momencie kliknięcia (np. w ten sposób):
data() {
return {
noReactive: {
first: "test 1"
},
reactive: {
first: "el 1"
}
};
},
methods: {
addElementNoReactive() {
this.noReactive.second = "added no reactive ";
console.log(this.noReactive);
}
}
Spodziewanym efektem jest dodanie kolejnego zagnieżdżonego elementu. Przetestujmy to zatem poniżej klikając w zarówno "Add without reactivity" oraz "Add with reactivity" i śledząc konsole i widok.
Jak widać w konsoli, elementy zostały dodane, lecz w pierwszym przypadku widok nie został zaktualizowany.
Przedstawiony błąd wynika z ograniczeń Javascriptu oraz z faktu, że Vue do śledzenia zmian używa Object.observe
(które nie jest już wspierane). Vue nadpisuje gettery
i settery
używając Object.defineProperty
tylko na początku i końcu cyklu życia komponentu, więc nie ma możliwości obserwowania i reagowania na zmiany obiektów, które nie zostały wcześniej zainicjalizowane.
W związku z tym, każda zmienna przechowująca dane naszego komponentu powinna zostać umieszczona w data
i zainicjalizowana, nawet jeśli będzie pusta.
Twórcy w celu wymuszenia reaktywności na nowo dodanym elemencie dodali funkcję $set
, która wymusza dodanie watchera do nowej zmiennej.
Jej użycie wygląda następująco:
Vue.set(object, propertyName, value)
.
Dlatego we wcześniejszym przykładzie klikając w button "Add with reactivity" wszystko działa tak jest tego oczekiwaliśmy.
Omówiony przykład to coś z czego każdy programista Vue powinien sobie zdawać sprawę, jeśli nie chce zmarnować dnia na szukanie buga. Coś co w Reactjs po prostu działa, tutaj może być źródłem frustracji, lecz na ten moment pozostało się z tym tylko pogodzić.
Pocieszający jest fakt, że w Vue 3 ten problem nie powinien występować.