Pomoc w zrozumieniu działania metody componentDidUpdate - React

0

Hej :)

Mam pytanie, jest ono na bazie testów jakie mam na kursie obecnie:

Do zmiennej List przesyłane są najpierw props.items o wartości ['a', 'b', 'c'], a następnie ['a', 'x', 'y', 'z']. Ile razy w konsoli wyświetli "2"?

Już wiem, że trzykrotnie, niemniej jednak nie do końca rozumiem dlaczego

0

ComponentDidUpdate jest odpalane po tym jak zmieniły się propsy wyrenderowanego już komponentu. Za pierwszym razem renderuje się lista z trzema elementami, więc tutaj ComponentDidUpdate nie będzie uruchomiony z powodu pierwszego renderu. W drugim cyklu dostajesz nową tablicę elementów, w których 3 elementy są różne. Dla wartości 'a' nie zostanie przerenderowany ListItem, ponieważ nic się nie zmieniło dla pierwszego indexu. Pozostałe 3 ListItem'y mają nowe propsy i React zdecydował, że należy przerenderować te komponenty.

0

Dzięki za odp :)

Ogólnie to samą metodę componentDidUpdate rozumiem, większy mam problem z tym co się dzieje w funkcji strzałkowej generującej List i przyjmującej props.

I tutaj pytanie: w ostatnim return mamy <ListItem key={index} text={text} />. To jest kluczowe miejsce w tym kodzie, bo ono decyduje poniekąd, czy się przerenderuje, czy nie, prawda? I teraz, gdy wchodzą nowe propsy, renderuje lub nie index oraz text, index nam się nie zmienia przy pierwszych trzech, bo to tablica, zmienia się tylko dla czwartego elementu (dodaje 'z') oraz dla zmiany dwóch textów ('x' oraz 'y') i dla tych 3 operacji jest rerender i odpala się metoda componentDidUpdate.

Czy takie łopatologiczne rozumowanie ma tutaj sens, czy gdzieś jest błąd logiczny?

0

Dobrze rozumiesz :) Z key też trzeba uważać. Index w tym przypadku to bardzo zły pomysł. Klucz powinien być nadany elementowi tak, aby można go było jednoznacznie wskazać na przykład przez jakieś niezmienne ID. W przypadku gdy masz 100 elementów na liście a kluczem jest index to po usunięciu z listy pierwszego elementu spowodujesz niepotrzebnie rerender pozostałych 99. Gdyby miały stały klucz to takiej sytuacji by nie było.

1

Swoją drogą to jest porażka Reacta jako biblioteki, że żeby z niego korzystać, trzeba wiedzieć, co się kiedy uruchamia i ile razy.
Aczkolwiek coraz lepiej jest. Na ten moment możesz w większości przypadków już zrezygnować w nowych projektach z klas, i robić komponenty funkcyjne i używać w nich hooks https://reactjs.org/docs/hooks-intro.html
Trochę łatwiejszy w obsłudze się robi React, chociaż i tak nie jest idealnie, bo i tak cały model pracy z React jest do pewnego stopnia skopany. No i hooki też trzeba nauczyć się obsługiwać (np. useEffect nie przekłada się dokładnie na componentDidMount, bo domyślnie odpala się po każdym renderze, chyba, że da się pustą tablicę jako dodatkowy argument: https://reactjs.org/docs/hooks-effect.html#explanation-why-effects-run-on-each-update )

Ja się zastanawiam, czy nie zacząć się uczyć Svelte, bo mnie przekonała ta prezentacja. Wydaje się to bardziej straight-forward, bez robienia wszystkiego naokoło:

0

Dzięki za odp. To teraz rozwinięcie :D
Mamy poniżej dokładnie to samo, ale w <ListItem key={text} text={text} mamy teraz tak, czyli dla key nie ma już index jest tylko text. Prawidłowa odpowiedź to 1. Nie wiem dlaczego zmiana w obiekcie key na text powoduje brak rerenderingu pierwszych 3 wartości.

screenshot-20190427142737.png

0

W pierwszym cyklu renderuje się a, b, c i tutaj nie uruchomi się componentDidUpdate bo to pierwszy render. W drugim są zupełnie nowe klucze: x, y, z i dla nich jest to pierwszy render więc componentDidUpdate dla nich nie zostanie uruchomiony. Wygląda na to, że z jakiegoś powodu React uznał, że musi przerenderować a. Niestety w tej chwili nie mam pojęcia dlaczego - według mnie nie powinien tego robić. Jako tymczasowe rozwiązanie możesz nadpisać shouldComponentUpdate aby temu zapobiec. Wtedy w ogóle nie powinno być żadnego rerenderu dla tego przypadku.

0
Fuffu napisał(a):

Dla wartości 'a' nie zostanie przerenderowany ListItem, ponieważ nic się nie zmieniło dla pierwszego indexu. Pozostałe 3 ListItem'y mają nowe propsy i React zdecydował, że należy przerenderować te komponenty.

To nie tak, Dla wartości ['a', 'x','y'] będzie componentDidUpdate. A dla wartości 'z', będzie componentDidMount.

Wojciech Pawlak napisał(a):

Dzięki za odp. To teraz rozwinięcie :D
Mamy poniżej dokładnie to samo, ale w <ListItem key={text} text={text} mamy teraz tak, czyli dla key nie ma już index jest tylko text. Prawidłowa odpowiedź to 1. Nie wiem dlaczego zmiana w obiekcie key na text powoduje brak rerenderingu pierwszych 3 wartości.

Tak jak napisał Fuffu:

Fuffu napisał(a):

W drugim są zupełnie nowe klucze: x, y, z i dla nich jest to pierwszy render więc componentDidUpdate dla nich nie zostanie uruchomiony. Wygląda na to, że z jakiegoś powodu React uznał, że musi przerenderować a.

Podsumowując wygląda na to, że jak komponent dostanie nowe propsy to się wykona componentDidUpdate i nie ważne, że są to propsy takie same, jakie otrzymał przy ostatnim renderze.
Jeżeli zmienimy key, to się wykona componentDidMount tak jak byśmy renderowali zupełnie nowy komponent.

EDIT: Sprawdźcie sami: https://jscomplete.com/playground/s263267

0

Dziękuję za odp. i za link z playground.

Pytanie tylko co dokładnie daje zmiana key={index} na key={text}? Widzę, że update robi jedynie dla wartości a?

0

React po key rozpoznaje komponenty wygenerowane w pętli. Dlatego jeżeli zmienisz key, a zauważ, że jak ustawisz, key={text} to zmieni się on dla 3 komponentów. Dlatego React potraktuje je, jak zupełnie nowe komponenty i wykona się componentDidMount . Tylko dla text="a", nastąpi update. Bo komponent z takim kluczem już wcześniej był utworzony.

1 użytkowników online, w tym zalogowanych: 0, gości: 1