Jaka jest logika używania zarówno „akcji”, jak i „mutacji” w Vuex?
Rozumiem logikę komponentów, które nie są w stanie modyfikować stanu (co wydaje się sprytne), ale posiadanie zarówno akcji, jak i mutacji wydaje się, że piszesz jedną funkcję, aby wyzwolić inną funkcję, a następnie zmienić stan.
Jaka jest różnica między „akcjami” a „mutacjami”, jak one ze sobą współpracują, a co więcej, jestem ciekaw, dlaczego programiści Vuex zdecydowali się to zrobić w ten sposób?
mutations
iactions
są zdefiniowane w dokumentacji vuex jako metody zmiany stanu. Nie potrzebujesz żadnego działania, aby dokonać mutacji.Odpowiedzi:
Pytanie 1 : Dlaczego programiści Vuejs zdecydowali się to zrobić w ten sposób?
Odpowiedź:
Pytanie 2 : Jaka jest różnica między „akcją” a „mutacją”?
Najpierw zobaczmy oficjalne wyjaśnienie:
Oto moje wyjaśnienie powyższego:
źródło
Mutacje są synchroniczne, podczas gdy akcje mogą być asynchroniczne.
Ujmując to inaczej: nie potrzebujesz akcji, jeśli twoje operacje są synchroniczne, w przeciwnym razie zaimplementuj je.
źródło
Wierzę, że zrozumienie motywacji stojących za mutacjami i działaniami pozwala lepiej ocenić, kiedy użyć których i jak. Uwalnia także programistę od ciężaru niepewności w sytuacjach, gdy „reguły” stają się niejasne. Po zastanowieniu się nad ich celami doszedłem do wniosku, że chociaż zdecydowanie mogą istnieć niewłaściwe sposoby użycia akcji i mutacji, nie sądzę, że istnieje podejście kanoniczne.
Najpierw spróbujmy zrozumieć, dlaczego w ogóle przechodzimy przez mutacje lub akcje.
Ściśle mówiąc, możesz zmienić
state
bezpośrednio ze swoich komponentów. Jeststate
to po prostu obiekt JavaScript i nie ma nic magicznego, co cofnie wprowadzone w nim zmiany.Jednak robiąc to, rozpraszasz mutacje swojego stanu w każdym miejscu. Tracisz możliwość po prostu otwarcia pojedynczego modułu zawierającego stan i na pierwszy rzut oka zobaczysz, jakie operacje można na nim wykonać. Posiadanie scentralizowanych mutacji rozwiązuje ten problem, aczkolwiek kosztem pewnych schematów.
Myślę, że jeśli zamienisz coś krótkiego na standardowy, będziesz chciał, aby kocioł również był mały. Dlatego przypuszczam, że mutacje mają być bardzo cienkimi opakowaniami wokół natywnych operacji w państwie, prawie bez logiki biznesowej. Innymi słowy, mutacje mają być używane głównie jak setery.
Teraz, gdy scentralizowałeś swoje mutacje, masz lepszy przegląd zmian stanu, a ponieważ Twoje narzędzia (vue-devtools) są również świadome tej lokalizacji, ułatwia to debugowanie. Warto również pamiętać, że wiele wtyczek Vuex nie obserwuje stanu bezpośrednio, aby śledzić zmiany, raczej polegają na mutacjach. Zmiany stanu „poza granicami” są więc dla nich niewidoczne.
Akcje, podobnie jak mutacje, również znajdują się w module sklepu i mogą odebrać
state
obiekt. Co oznacza, że mogliby również dokonać bezpośredniej mutacji. Więc jaki jest sens posiadania obu? Jeśli uznamy, że mutacje muszą być małe i proste, oznacza to, że potrzebujemy alternatywnych środków, aby pomieścić bardziej złożoną logikę biznesową. Działania są środkiem do osiągnięcia tego. A ponieważ jak ustaliliśmy wcześniej, vue-devtools i wtyczki są świadome zmian poprzez mutacje, aby zachować spójność, powinniśmy nadal używać mutacji w naszych działaniach. Ponadto, ponieważ akcje mają obejmować wszystko, a logika, którą zawierają, może być asynchroniczna, ma sens, aby akcje były po prostu asynchroniczne od samego początku.Często podkreśla się, że akcje mogą być asynchroniczne, podczas gdy mutacje zazwyczaj nie. Możesz zdecydować, że to rozróżnienie będzie wskazówką, że mutacje powinny być używane w przypadku wszystkiego, co jest synchroniczne (i działania w przypadku wszystkiego, co jest asynchroniczne); Jednak napotkasz pewne trudności, jeśli na przykład musisz wprowadzić więcej niż jedną mutację (synchronicznie), lub jeśli potrzebujesz pracować z Getterem z twoich mutacji, ponieważ funkcje mutacji nie otrzymują ani Getterów, ani Mutacji jako argumentów ...
... co prowadzi do ciekawego pytania.
Nie znalazłem jeszcze satysfakcjonującej odpowiedzi na to pytanie. Widziałem wyjaśnienia głównego zespołu, które w najlepszym razie uznałem za dyskusyjne. Jeśli podsumuję ich użycie, Gettery mają być obliczanymi (i często buforowanymi) rozszerzeniami stanu. Innymi słowy, w zasadzie nadal są stanem, chociaż wymaga to pewnych obliczeń z góry i zwykle są tylko do odczytu. Przynajmniej tak są zachęcani do używania.
Tak więc, zapobieganie bezpośredniemu dostępowi do Getterów przez mutacje oznacza, że jedna z trzech rzeczy jest teraz konieczna, jeśli potrzebujemy uzyskać dostęp z tej pierwszej do niektórych funkcji oferowanych przez tę drugą: (1) albo obliczenia stanu dostarczane przez Getter są zduplikowane w miejscu, które jest dostępne do Mutacji (nieprzyjemny zapach) lub (2) obliczona wartość (lub odpowiedni sam Getter) jest przekazywana jako wyraźny argument do Mutacji (funky), lub (3) sama logika Gettera jest powielana bezpośrednio w Mutacji , bez dodatkowej korzyści z buforowania, jak zapewnia Getter (smród).
Poniżej znajduje się przykład (2), który w większości scenariuszy, z którymi się spotkałem, wydaje się „najmniej złą” opcją.
Wydaje mi się, że powyższe wydaje mi się nie tylko trochę zagmatwane, ale także nieco „nieszczelne”, ponieważ część kodu obecnego w Akcji wyraźnie wycieka z wewnętrznej logiki Mutacji.
Moim zdaniem to zapowiedź kompromisu. Uważam, że zezwolenie mutacjom na automatyczne otrzymywanie Getterów stanowi pewne wyzwanie. Może to dotyczyć projektu samego Vuex lub narzędzi (Vue-devtools i in.), Lub zachowania pewnej kompatybilności wstecznej lub kombinacji wszystkich wymienionych możliwości.
Nie wierzę, że samodzielne przekazywanie Getterów do swoich mutacji jest koniecznie oznaką, że robisz coś złego. Widzę to jako po prostu „łatanie” jednej z wad frameworka.
źródło
computed
wyjściem. Są tylko do odczytu. Lepszym sposobem przeglądania mutacji może być usunięcie tego,if else
co masz. Dokumenty vuex mówią, żecommit
w akcji możesz pomieścić więcej niż 1 . Zatem logiczne byłoby założenie, że w zależności od logiki możesz popełnić określoną mutację. Postrzegam działania jako sposób na dyktowanie, KTÓREJ mutacji ma odpalić.Myślę, że odpowiedź TLDR jest taka, że mutacje mają być synchroniczne / transakcyjne. Więc jeśli chcesz uruchomić wywołanie Ajax lub wykonać inny kod asynchroniczny, musisz to zrobić w Action, a następnie zatwierdzić mutację, aby ustawić nowy stan.
źródło
Główne różnice między akcjami a mutacjami:
źródło
Według
docs
Działania są podobne do mutacji , z tą różnicą, że:
Rozważmy następujący fragment.
źródło
Zastrzeżenie - dopiero zacząłem używać vuejs, więc to tylko ja ekstrapoluję założenia projektowe.
Debugowanie wehikułu czasu wykorzystuje migawki stanu i przedstawia oś czasu działań i mutacji. Teoretycznie moglibyśmy mieć tuż
actions
obok nagrania ustawiaczy stanu i pobierających, aby synchronicznie opisać mutację. Ale wtedy:mutations
transakcji, ale wtedy możemy powiedzieć, że transakcja musi zostać ulepszona, a nie stan wyścigu w akcjach. Anonimowe mutacje wewnątrz akcji mogą łatwiej ujawnić tego rodzaju błędy, ponieważ programowanie asynchroniczne jest delikatne i trudne.Porównaj następujący dziennik transakcji z nazwanymi mutacjami.
Z dziennikiem transakcji, który nie ma nazwanych mutacji:
Mam nadzieję, że możesz ekstrapolować z tego przykładu potencjalną dodatkową złożoność asynchronii i anonimową mutację wewnątrz działań.
https://vuex.vuejs.org/en/mutations.html
źródło
Mutacje:
Działania:
W sposób Redux
Dlaczego obie?
Kiedy aplikacja się rozrasta, kodowanie i linie będą się zwiększać, tym razem musisz zająć się logiką w Akcjach, a nie w mutacjach, ponieważ mutacje są jedynym autorytetem do zmiany stanu, powinno być jak najbardziej czyste.
źródło
To też mnie zdezorientowało, więc zrobiłem proste demo.
component.vue
store.js
Po zbadaniu tego doszedłem do wniosku, że mutacje są konwencją skupioną tylko na zmianie danych, aby lepiej rozdzielić obawy i poprawić logowanie przed i po zaktualizowaniu danych. Natomiast działania są warstwą abstrakcji, która obsługuje logikę wyższego poziomu, a następnie odpowiednio wywołuje mutacje
źródło
1. z dokumentów :
Akcje mogą zawierać operacje asynchroniczne, ale mutacja nie.
2. Wzywamy mutację, możemy bezpośrednio zmienić stan. a także możemy w akcji zmieniać stany w następujący sposób:
Akcje są przeznaczone do obsługi większej liczby innych rzeczy, możemy tam zrobić wiele rzeczy (możemy użyć operacji asynchronicznych), a następnie zmienić stan przez mutację wysyłkową.
źródło
Ponieważ nie ma stanu bez mutacji! Po zatwierdzeniu - wykonywany jest kawałek logiki, który zmienia stan w przewidywalny sposób. Mutacje to jedyny sposób na ustawienie lub zmianę stanu (więc nie ma bezpośrednich zmian!), A ponadto - muszą być synchroniczne. To rozwiązanie napędza bardzo ważną funkcjonalność: mutacje logują się do devtools. A to zapewnia doskonałą czytelność i przewidywalność!
Jeszcze jedno - działania. Jak już powiedziano - działania powodują mutacje. Więc nie zmieniają sklepu i nie ma potrzeby, aby były synchroniczne. Ale mogą zarządzać dodatkowym elementem logiki asynchronicznej!
źródło
Może wydawać się niepotrzebne posiadanie dodatkowej warstwy
actions
tylko w celu wywołaniamutations
, na przykład:Więc jeśli wywołanie
actions
połączenialogout
, dlaczego nie nazwać samą mutację?Cała idea akcji polega na wywołaniu wielu mutacji z poziomu jednej akcji lub wykonaniu żądania Ajax lub dowolnej logiki asynchronicznej, jaką możesz sobie wyobrazić.
W końcu możemy mieć działania, które powodują wiele żądań sieciowych i ostatecznie wywołują wiele różnych mutacji.
Więc staramy się jak najwięcej rzeczy z naszego złożoności
Vuex.Store()
, jak to możliwe w naszychactions
i to opuszcza naszmutations
,state
igetters
czystsze i proste i wpisuje się w tego rodzaju modułowość sprawia, że biblioteki jak Vue i reagować popularne.źródło
Zawodowo używam Vuex od około 3 lat i wydaje mi się, że odkryłem, jakie są podstawowe różnice między działaniami i mutacjami, jak możesz skorzystać z ich wspólnego używania i jak możesz utrudnić sobie życie, jeśli nie używaj go dobrze.
Głównym celem Vuex jest zaoferowanie nowego wzorca do kontroli zachowania aplikacji: reaktywności. Chodzi o to, aby odciążyć orkiestrację stanu aplikacji do wyspecjalizowanego obiektu: sklepu. W wygodny sposób zapewnia metody łączenia komponentów bezpośrednio z danymi sklepu, aby można było z nich korzystać w dogodnym dla siebie czasie. Pozwala to komponentom skupić się na ich zadaniu: definiowaniu szablonu, stylu i podstawowego zachowania komponentów do zaprezentowania użytkownikowi. W międzyczasie sklep obsługuje duże obciążenie danymi.
To jednak nie jedyna zaleta tego wzoru. Fakt, że magazyny są pojedynczym źródłem danych dla całej aplikacji, oferuje duży potencjał ponownego wykorzystania tych danych w wielu komponentach. Nie jest to pierwszy wzorzec, który próbuje rozwiązać ten problem komunikacji między komponentami, ale tam, gdzie świeci, jest to, że zmusza cię do zaimplementowania bardzo bezpiecznego zachowania w twojej aplikacji, zasadniczo zabraniając twoim komponentom modyfikowania stanu tych udostępnionych danych i zamiast tego zmusić go do używania „publicznych punktów końcowych”, aby poprosić o zmianę.
Podstawowa idea jest taka:
To powiedziawszy, magia zaczyna się, gdy zaczynamy projektować naszą aplikację w ten sposób. Na przykład:
W końcu mamy doświadczenie użytkownika, które jest uważane za „reaktywne”. Z punktu widzenia naszego użytkownika pozycja została natychmiast usunięta. W większości przypadków oczekujemy, że nasze punkty końcowe będą działać, więc jest to idealne rozwiązanie. Gdy to się nie powiedzie, nadal mamy kontrolę nad tym, jak będzie reagować nasza aplikacja , ponieważ udało nam się oddzielić obawy o stan naszej aplikacji front-end od rzeczywistych danych.
Pamiętaj, że nie zawsze potrzebujesz sklepu. Jeśli okaże się, że piszesz sklepy, które wyglądają tak:
Wydaje mi się, że używasz magazynu tylko jako magazynu danych i być może pomijasz jego aspekt reaktywności, nie pozwalając mu również przejąć kontroli nad zmiennymi, na które reaguje Twoja aplikacja. Zasadniczo możesz i prawdopodobnie powinieneś przenieść do sklepów niektóre wiersze kodu napisane w Twoich komponentach.
źródło