React Hooks — zapamiętanie pozycji scroll podczas zmiany widoków list

Mikołaj Kocięda
August 5, 2020 | Software development

Podczas pracy nad jednym z projektów spotkałem interesujący problem. Wyobraź sobie, że masz listę z danymi, która może być wyświetlana jako prosta siatka, bądź bardziej zaawansowany widok ze zdjęciami, opisem itd. Implemntacja samego mechanizmu zmiany widoku jest bardzo prosta. Wystarczy zwykły przełącznik w react hooks, którego stan może być trzymany jako podstawowy useState, bądź nawet jeśli jest taka potrzeba – w storze Redux.

Gdzie więc jest problem?

Problem można napotkać w momencie kiedy zmieni się widok. Przeglądarka nie zapamiętuje wtedy na którym itemie z listy aktualnie byliśmy, tylko zachowuje pozycję scroll. Wyobraź sobie, że patrzysz aktualnie na Item 5, zmieniasz widok na “szczegółowy” i zamiast Item 5 pojawia się Item 2. Dzieje się tak, ponieważ szczegółowe itemy mają większą wysokość i zmieniają całkowicie widok listy. Przykład możesz zobaczyć tutaj.

Jak można rozwiązać ten problem?

  1. Przed zmianą widoku należy sprawdzić oraz zapisać informacje, który item jest aktualnie widoczny.
  2. Zmienić widok.
  3. Sprawdzić pozycję scroll zapisanego itemu.
  4. Ustawić scroll na sprawdzoną wcześniej pozycję.

Głównym problemem tych operacji jest wykonanie funkcji tuż przed zmianą widoku. Można oczywiście nasłuchiwać eventu “scroll” i zapisywać z każdym eventem nową informację o aktywnym elemencie, ale nie jest to zbyt optymalne podejście. Idealnie byłoby sprawdzić drzewo DOM zaraz przed zmianą widoku. Dla utrudnienia, powiedzmy, że należy to zrobić BEZ modyfikacji funkcji zmieniającej widok.

getSnapshotBeforeUpdate

Dla takich sytuacji React przygotował metodę cyklu życia komponentu zwaną getSnapshotBeforeUpdate. Możesz o niej więcej przeczytać tutaj Jednak naszym celem nie jest przepisywanie wszystkiego na komponent klasowy. Więc jak to zrobić z hookami…?

Using react hooks – useMemo

Po głębokiej analizie i wyszukiwaniu dostępnych metod jak możemy zrobić to bez kompletnej refaktoryzacji, natrafiłem na informacje, że hook useMemo jest wykonywany PRZED renderowaniem komponentu. Dzięki dependencies array funkcję z useMemo można wykonać tylko wtedy, kiedy zmieni się stan widoku. Po połączeniu tego z kolejnym hookiem – useLayoutEffect – który jest wykonywany PO renderowaniu uzyskujemy coś na wzór “przypięcia” pozycji scroll do aktualnego elementu w widoku.  

Pełny, działający, przykład dostępny jest tutaj.
You can find an English version of the article about React Hooks at medium.com here.

Chcesz poznać nas lepiej? Dowiedz się, co nas wyróżnia.