TL; DR
Skąd komponent nadrzędny może wiedzieć, kiedy renderowanie każdego komponentu podrzędnego pod nim zakończyło się, a DOM jest widoczny dla użytkownika w jego najnowszej wersji?
Powiedzmy, że mam komponent component A
potomny Grid
składający się z 3x3
komponentów wnuka. Każdy z tych składników wnuka pobiera dane z punktu końcowego interfejsu API, który się uspokaja i renderuje, gdy dane stają się dostępne.
Chciałbym aby pokryć całą powierzchnię Component A
z loader
zastępczy, który zostanie zaprezentowany dopiero, gdy ostatni z elementów w siatce ma idącą dane skutecznie i renderowane go tak, że to już na DOM i mogą być przeglądane.
Interfejs użytkownika powinien być bardzo płynnym przejściem z „modułu ładującego” do całkowicie wypełnionej siatki bez migotania.
Mój problem polega na tym, by dokładnie wiedzieć, kiedy odsłonić komponenty pod modułem ładującym.
Czy jest jakiś mechanizm, na którym mogę polegać, aby robić to z absolutną dokładnością? Nie koduję na stałe limitu czasu dla modułu ładującego. Rozumiem, że poleganie na ComponentDidMount
każdym dziecku jest również zawodne, ponieważ w rzeczywistości nie gwarantuje, że element będzie w pełni widoczny dla użytkownika w momencie połączenia.
Aby jeszcze bardziej wyjaśnić pytanie:
Mam komponent, który renderuje jakiś rodzaj danych. Po zainicjowaniu nie ma go, więc
componentDidMount
trafia do niego punkt końcowy interfejsu API. Po otrzymaniu danych zmienia stan, aby je odzwierciedlić. To zrozumiałe powoduje ponowne renderowanie stanu końcowego tego komponentu. Moje pytanie brzmi: skąd mam wiedzieć, kiedy to ponowne renderowanie miało miejsce i jest odzwierciedlone w DOM zwróconym do użytkownika? Ten moment w czasie! = Moment, w którym stan komponentu zmienił się i zawiera dane.
ComponentDidMount
używamaxios
do pobierania danych. kiedy dane przechodzą, zmieniam stan tego komponentu, który powoduje renderowanie danych. Teoretycznie 8 komponentów potomnych może zostać pobranych w ciągu 3 sekund, a ostatni zajmie 15 sekund ...Odpowiedzi:
Istnieją dwa zaczepy cyklu życia w React, które są wywoływane po renderowaniu DOM komponentu:
Dla Państwa przypadku użycia rodzic składnik P jest zainteresowany, gdy N komponenty dziecko ma każdy spełniony pewien warunek X . X można zdefiniować jako sekwencję:
Łącząc stan komponentu i używając
componentDidUpdate
haka, możesz wiedzieć, kiedy sekwencja została zakończona, a komponent spełnia warunek X.Możesz śledzić zakończenie operacji asynchronicznej, ustawiając zmienną stanu. Na przykład:
Po ustawieniu stanu React wywoła
componentDidUpdate
funkcję składników . Porównując bieżące i poprzednie obiekty stanu w ramach tej funkcji, możesz zasygnalizować komponentowi nadrzędnemu, że operacja asynchroniczna została zakończona, a stan nowego komponentu jest renderowany:W komponencie P możesz użyć licznika, aby śledzić, ile dzieci znacząco zaktualizowało:
Wreszcie, znając długość N , możesz wiedzieć, kiedy nastąpiły wszystkie znaczące aktualizacje, i działaj odpowiednio w metodzie renderowania P :
źródło
Ustawiłbym to tak, abyś polegał na globalnej zmiennej stanu, aby powiedzieć swoim komponentom, kiedy ma być renderowany. Redux jest lepszy w tym scenariuszu, w którym wiele komponentów ze sobą rozmawia, a wspomniałeś w komentarzu, że czasami go używasz. Więc naszkicuję odpowiedź za pomocą Redux.
Trzeba przenieść wywołań API do kontenera macierzystego
Component A
. Jeśli chcesz, aby wnuki były renderowane tylko po zakończeniu wywołań API, nie możesz zachować tych wywołań API w samych wnukach. Jak można wywołać API z komponentu, który jeszcze nie istnieje?Po wykonaniu wszystkich wywołań interfejsu API można użyć akcji do zaktualizowania globalnej zmiennej stanu zawierającej kilka obiektów danych. Za każdym razem, gdy dane są odbierane (lub wychwytywany jest błąd), możesz wysłać akcję, aby sprawdzić, czy obiekt danych jest całkowicie wypełniony. Po jej całkowitym wypełnieniu możesz zaktualizować
loading
zmiennąfalse
i warunkowo renderowaćGrid
komponent.Na przykład:
Twój reduktor zatrzyma globalny obiekt stanu, który powie, czy wszystko jest już gotowe, czy nie:
W twoich działaniach:
Na bok
Jeśli jesteś naprawdę żonaty z myślą, że Twoje wywołania API znajdują się wewnątrz każdego wnuka, ale że cała siatka wnuków nie jest renderowana, dopóki wszystkie wywołania API nie zostaną zakończone, musisz użyć zupełnie innego rozwiązania. W takim przypadku wasze wnuki musiałyby być renderowane od samego początku, aby wykonywać połączenia, ale miały klasę css
display: none
, która zmienia się dopiero po tym, jak globalna zmienna stanuloading
jest oznaczona jako fałsz. Jest to również wykonalne, ale w pewnym sensie poza React.źródło
Można potencjalnie rozwiązać ten problem za pomocą React napięciu.
Zastrzeżenie polega na tym, że nie jest dobrym pomysłem zawieszenie się obok drzewa komponentów, które wykonuje renderowanie (to znaczy: jeśli twój komponent rozpoczyna proces renderowania, moim zdaniem zawieszenie tego komponentu nie jest dobrym pomysłem), więc prawdopodobnie lepszym pomysłem jest wykasowanie żądań w komponencie renderującym komórki. Coś takiego:
Nie jestem pewien, jak bardzo Suspens łączy się z Redux. Cała idea tej (eksperymentalnej!) Wersji Suspense polega na tym, że pobieranie rozpoczyna się natychmiast podczas cyklu renderowania komponentu nadrzędnego i przekazuje obiekt, który reprezentuje pobieranie do dzieci. Zapobiega to konieczności posiadania pewnego rodzaju obiektu Barrier (który byłby potrzebny w innych podejściach).
Powiem, że nie sądzę, że czekanie, aż wszystko się pobierze, aby wyświetlić cokolwiek, jest właściwym podejściem, ponieważ wtedy interfejs użytkownika będzie tak wolny jak najwolniejsze połączenie lub może w ogóle nie działać!
Oto pozostała część brakującego kodu:
I piaskownica: https://codesandbox.io/s/falling-dust-b8e7s
źródło
Przede wszystkim cykl życia może mieć metodę asynchroniczną / oczekującą.
Co musimy wiedzieć o
componentDidMount
, acomponentWillMount
,Moim zdaniem wystarczy je wdrożyć w normalnym cyklu życia.
Material-UI CircularProgress
Ponieważ ponowne renderowanie dziecka powoduje, że rodzic robi to samo, złapanie go
didUpdate
byłoby w porządku.A ponieważ jest wywoływany po renderowaniu, strony nie powinny być później zmieniane, jeśli ustawisz funkcję sprawdzania jako swoje żądanie.
Używamy tej implementacji w naszym produkcie, który ma interfejs API, co powoduje, że 30s otrzymuje odpowiedź, wszystko działało dobrze, o ile widzę.
źródło
Gdy wykonujesz wywołanie interfejsu API
componentDidMount
, gdy połączenie API zostanie rozwiązane, będziesz mieć dane,componentDidUpdate
ponieważ ten cykl życia minieprevProps
iprevState
. Możesz więc zrobić coś takiego:Jeśli chcesz to wiedzieć przed ponownym renderowaniem komponentu, możesz użyć
getSnapshotBeforeUpdate
.https://reactjs.org/docs/react-component.html#getsnapshotbeforeupdate .
źródło
Istnieje wiele metod, które możesz zastosować:
źródło