Jaka jest różnica między ChangeDetectorRef.markForCheck()
i ChangeDetectorRef.detectChanges()
?
Znalazłem tylko informacje na temat SO co do różnicy między NgZone.run()
, ale nie między tymi dwoma funkcjami.
Aby uzyskać odpowiedzi zawierające tylko odniesienie do dokumentu, zilustruj kilka praktycznych scenariuszy, aby wybrać jeden z nich.
angular
angular2-changedetection
parlament
źródło
źródło
Odpowiedzi:
Z dokumentów:
Oznacza to, że jeśli jest przypadek, w którym coś w twoim modelu (twojej klasie) uległo zmianie, ale nie odzwierciedlało widoku, może być konieczne powiadomienie Angulara, aby wykrył te zmiany (wykrył zmiany lokalne) i zaktualizował widok.
Możliwe scenariusze to:
1- Detektor zmian jest odłączony od widoku (patrz odłączanie )
2- Nastąpiła aktualizacja, ale nie było jej w Angular Zone, dlatego Angular o tym nie wie.
Tak jak wtedy, gdy funkcja innej firmy zaktualizowała Twój model i chcesz zaktualizować widok po tym.
Ponieważ ten kod znajduje się poza strefą Angular (prawdopodobnie), najprawdopodobniej musisz upewnić się, że wykryłeś zmiany i zaktualizowałeś widok, w ten sposób:
UWAGA :
Istnieją inne sposoby, aby powyższe zadziałało, innymi słowy, istnieją inne sposoby wprowadzenia tej zmiany w cyklu zmian Angulara.
** Możesz umieścić tę funkcję strony trzeciej w strefie zone.run:
** Możesz zawinąć funkcję wewnątrz setTimeout:
3 - Istnieją również przypadki, w których aktualizujesz model po
change detection cycle
zakończeniu, w których w takich przypadkach pojawia się ten przerażający błąd:„Wyrażenie zmieniło się po sprawdzeniu”;
To generalnie oznacza (z języka Angular2):
Widziałem zmianę w Twoim modelu, która była spowodowana jednym z moich zaakceptowanych sposobów (zdarzenia, żądania XHR, setTimeout i ...), a następnie uruchomiłem wykrywanie zmian, aby zaktualizować widok i skończyłem, ale potem był inny funkcja w twoim kodzie, która ponownie zaktualizowała model i nie chcę ponownie uruchamiać wykrywania zmian, ponieważ nie ma już brudnego sprawdzania, takiego jak AngularJS: D i powinniśmy używać jednokierunkowego przepływu danych!
Na pewno napotkasz ten błąd: P.
Kilka sposobów, aby to naprawić:
1- Właściwy sposób : upewnij się, że aktualizacja znajduje się w cyklu wykrywania zmian (aktualizacje Angular2 to jednokierunkowy przepływ, który ma miejsce raz, nie aktualizuj później modelu i przenieś swój kod w lepsze miejsce / czas).
2- Leniwy sposób : po tej aktualizacji uruchom funkcję detectionChanges (), aby angular2 był szczęśliwy, zdecydowanie nie jest to najlepszy sposób, ale jeśli zapytałeś, jakie są możliwe scenariusze, to jest jeden z nich.
W ten sposób mówisz: Szczerze wiem, że uruchomiłeś wykrywanie zmian, ale chcę, abyś zrobił to ponownie, ponieważ musiałem aktualizować coś w locie po zakończeniu sprawdzania.
3- Umieść kod wewnątrz a
setTimeout
, ponieważsetTimeout
jest załatany przez strefę i będzie działaćdetectChanges
po zakończeniu.Z dokumentów
Jest to głównie potrzebne, gdy ChangeDetectionStrategy twojego komponentu jest OnPush .
Sam OnPush oznacza, że uruchamiaj wykrywanie zmian tylko wtedy, gdy wydarzy się którykolwiek z poniższych:
1- Jedno z @inputs komponentu zostało całkowicie zastąpione nową wartością lub po prostu mówiąc, jeśli odniesienie do właściwości @Input uległo całkowitej zmianie.
Więc jeśli ChangeDetectionStrategy twojego komponentu jest OnPush i masz:
A potem aktualizujesz / mutujesz to tak:
To nie będzie aktualizować obj odniesienia, stąd wykrywania zmian nie zamierzam biegać, więc widok nie jest odzwierciedlając aktualizacji / mutacji.
W takim przypadku musisz ręcznie powiedzieć Angularowi, aby sprawdził i zaktualizował widok (markForCheck);
Więc jeśli zrobiłeś to:
Musisz to zrobić:
Raczej poniżej spowodowałoby uruchomienie wykrywania zmian:
Który całkowicie zastąpił poprzedni obiekt nowym
{}
;2- Zdarzenie zostało uruchomione, np. Kliknięcie lub coś podobnego albo którykolwiek z komponentów podrzędnych wyemitował zdarzenie.
Wydarzenia takie jak:
Krótko mówiąc:
Użyj,
detectChanges()
gdy zaktualizowałeś model po uruchomieniu przez angular wykrywania zmian lub jeśli aktualizacja w ogóle nie była w świecie kątowym.Użyj,
markForCheck()
jeśli używasz OnPush i pomijaszChangeDetectionStrategy
przez mutację niektórych danych lub zaktualizowałeś model wewnątrz setTimeout ;źródło
detectChanges
widok aktualizacji. Zobacz to szczegółowe wyjaśnienie .this.cdMode === ChangeDetectorStatus.Checked
nie zaktualizuje widoku, dlatego użyjesz markForCheck.detectChanges
. AcdMode
w Angular nie ma4.x.x
. Piszę o tym w swoim artykule. Cieszę się, że Ci się podobało. Nie zapomnij, że możesz polecić to na medium lub śledzić mnie :)Największa różnica między nimi polega na tym, że
detectChanges()
faktycznie wyzwala wykrywanie zmian, amarkForCheck()
nie powoduje wykrywania zmian.DetectChanges
Ten służy do uruchamiania wykrywania zmian w drzewie komponentów, zaczynając od składnika, który jest uruchamiany
detectChanges()
. Tak więc wykrywanie zmian będzie działać dla bieżącego składnika i wszystkich jego elementów podrzędnych. Angular przechowuje odwołania do głównego drzewa komponentów w,ApplicationRef
a gdy ma miejsce jakakolwiek operacja asynchroniczna, wyzwala wykrywanie zmian w tym głównym komponencie za pomocą metody opakowującejtick()
:view
tutaj jest widok komponentu głównego. Może istnieć wiele komponentów głównych, jak opisałem w sekcji Jakie są konsekwencje ładowania wielu komponentów .@milad opisał powody, dla których potencjalnie może być konieczne ręczne wywołanie wykrywania zmian.
markForCheck
Jak powiedziałem, ten facet w ogóle nie uruchamia wykrywania zmian. Po prostu przechodzi w górę z bieżącego komponentu do komponentu głównego i aktualizuje ich stan widoku do
ChecksEnabled
. Oto kod źródłowy:Rzeczywiste wykrywanie zmian dla komponentu nie jest planowane, ale gdy nastąpi to w przyszłości (w ramach bieżącego lub następnego cyklu CD), widoki komponentu macierzystego zostaną sprawdzone, nawet jeśli miały odłączone detektory zmian. Detektory zmian można odłączać, używając
cd.detach()
lub określającOnPush
strategię wykrywania zmian. Wszystkie natywne programy obsługi zdarzeń zaznaczają wszystkie widoki komponentów nadrzędnych do sprawdzenia.To podejście jest często używane w
ngDoCheck
haku cyklu życia. Możesz przeczytać więcej w Jeśli uważasz, żengDoCheck
oznacza to, że Twój komponent jest sprawdzany - przeczytaj ten artykuł .Zobacz też Wszystko, co musisz wiedzieć o wykrywaniu zmian w Angular, aby uzyskać więcej informacji.
źródło
markForCheck
. Więc jeśli nie używasz potoku asynchronicznego, prawdopodobnie powinieneś użyć tego. Należy jednak pamiętać, że aktualizacja sklepu powinna nastąpić w wyniku jakiegoś zdarzenia asynchronicznego, aby rozpocząć wykrywanie zmian. Tak jest najczęściej. Ale są wyjątki blog.angularindepth.com/…async pipe
ponieważ w subskrybowaniu zwykle mamy kilka rzeczy do zrobienia, na przykładcall setFromValues
do some comparison
... a jeśliasync
sama wywołuje,markForCheck
jaki jest problem, jeśli nazywamy to sami? ale znowu zwykle mamy 2-3 lub czasami więcej selektorów wngOnInit
pobieraniu różnych danych ... i wzywamymarkForCheck
je wszystkie .. czy to w porządku?cd.detectChanges()
uruchomi wykrywanie zmian natychmiast od bieżącego składnika aż do jego elementów podrzędnych.cd.markForCheck()
nie uruchomi wykrywania zmian, ale oznaczy swoich przodków jako wymagających wykrywania zmian. Następnym razem, gdy wykrywanie zmian zostanie uruchomione w dowolnym miejscu, będzie działać również dla zaznaczonych komponentów.cd.markForCheck()
. Często zmiany wpływają na wiele komponentów i gdzieś zostanie wywołane wykrywanie zmian. Zasadniczo mówisz: po prostu upewnijmy się, że ten komponent jest również aktualizowany, gdy tak się stanie. (Widok jest natychmiast aktualizowany w każdym napisanym przeze mnie projekcie, ale nie w każdym teście jednostkowym).cd.detectChanges()
nie działa wykrywanie zmian, użyj . błąd w takim przypadku. Prawdopodobnie oznacza to, że próbujesz edytować stan komponentu przodka, który działa wbrew założeniom, zgodnie z którymi zostało zaprojektowane wykrywanie zmian w Angular.cd.markForCheck()
detectChanges()
detectChanges()
.markForCheck()
może nie aktualizować widoku na czas. Testowanie jednostkowe coś wpływa na widok, na przykład może wymagać ręcznego wywołania,fixture.detectChanges()
gdy nie było to konieczne w samej aplikacji.detectChanges()
ponieważ nie używasz niepotrzebnie wykrywania zmian w elementach nadrzędnych składnika.źródło