Strona główna / Artykuły

Utrzymuj listy z React Query aktualne za pomocą refetchOnMount po nawigacji

Dowiedz się, dlaczego TanStack Query wyświetla przestarzałe wiersze listy po edycjach, gdy invalidateQueries nie wystarcza, oraz jak refetchOnMount ponownie waliduje dane przy każdym ponownym załadowaniu.

Wydawca: REACTAPP.TOP5 min czytania1052 słów

Źródła: How `refetchOnMount` in React Query Solves Stale Data Problems Across Components

Zachowanie spójności pamięci cache klienta na różnych trasach jest trudniejsze niż pierwsze pobranie danych. Wyobraź sobie konsolę administracyjną, na której jednym ekranie znajduje się tabela użytkowników, a na drugim formularz edycji. Zapisanie nowej nazwy udaje się, nawigacja wraca do listy, ale stara nazwa nadal jest widoczna na ekranie.

Taki scenariusz występuje za każdym razem, gdy TanStack Query (React Query) korzysta z już przygotowanej pamięci cache zamiast ponownie łączyć się z siecią. Opcja refetchOnMount jest prostym narzędziem, które zmusza do sprawdzenia aktualności danych za każdym razem, gdy komponent służący do ich pobierania jest ładowany, bez konieczności dodawania ręcznego przycisku odświeżenia.

Problem

Rozważmy dwie trasy, które dzielą się jednym zasobem serwera:

  • Strona użytkowników — Wyświetla każdą wiersz z listy dostępnej przez odpowiedni endpoint.
  • Strona edycji użytkownika — Zachowuje zmiany dotyczące konkretnego użytkownika.

Trasa listy zazwyczaj wygląda w ten sposób:

const { data } = useQuery({
  queryKey: ["users"],
  queryFn: getUsers,
});

Szczęśliwa ścieżka funkcjonuje bez problemów, dopóki ktoś nie edytuje wiersza, nie zapisuje zmian i nie wraca. Mutacja powiodła się na serwerze, a mimo to tabela nadal pokazuje poprzednie wartości. Pytanie brzmi, dlaczego interfejs nie odnotował tej zmiany.

Dlaczego to się dzieje?

React Query przechowuje udane odpowiedzi pod kluczem queryKey. Opuścienie strony i jej ponowne wejście nie gwarantuje wysłania nowego żądania. Biblioteka sprawdza, czy klucz już zawiera dane; jeśli tak, to aktualny stan jest natychmiast wyświetlany.

Zysk w postaci szybkości jest rzeczywisty, ale kosztem jest przestarzałość danych w momencie, gdy pamięć cache i serwer się różnią. Powszechne przyczyny to:

  • Inny komponent edytował ten sam zasób.
  • Inna trasa wykonała mutację.
  • Druga karta w przeglądarce zmieniła dane.
  • Zewnętrzna strona zaktualizowała backend.

Dopóki coś nie unieważni lub ponownie nie pobraje klucza, interfejs użytkownika nadal ufa pamięci podręcznej.

Prawdziwy przykład

Kompaktowy drzewo tras wygląda w ten sposób:

Users
 ├── User List
 └── Edit User

Strona listy ładuje użytkowników z:

const { data } = useQuery({
  queryKey: ["users"],
  queryFn: fetchUsers,
});

Strona edycji przechowuje informacje z:

await updateUser(userId, values);

Następnie wraca do listy:

navigate("/users");

Po tej nawigacji tabela nadal może być wyświetlana:

John
Alice
Michael

mimo że serwer teraz przechowuje:

Johnny

React Query po prostu ponownie wykorzystał wcześniejszy zestaw danych listy dla ["users"].

Tradycyjne rozwiązania

Zespoły często ręcznie wymuszają odświeżenie po udanej operacji zapisu:

queryClient.invalidateQueries({
  queryKey: ["users"],
});

lub

queryClient.refetchQueries({
  queryKey: ["users"],
});

Nieważnienie danych i wyraźne ponowne pobranie pozostają odpowiednimi narzędziami zaraz po dokonaniu mutacji przez dany komponent. Są niewystarczające, gdy aktualność danych musi zostać przywrócona po nawigacji, działaniach w tle lub aktualizacjach, które nastąpiły poza obecnym drzewem komponentów. W takich przypadkach chce się, aby zapytanie sprawdziło dane na serwerze po ponownym załadowaniu strony.

Użyj refetchOnMount

Opcja ta ma dosłownie taką nazwę:

refetchOnMount

Po instruuje bibliotekę do ponownego pobrania danych za każdym razem, gdy komponent obsługujący to zapytanie zostaje załadowany. Zapytanie do listy staje się wtedy:

const { data } = useQuery({
  queryKey: ["users"],
  queryFn: fetchUsers,
  refetchOnMount: true,
});

Kolejność działań wygląda następująco:

  1. Otwórz stronę Users.
  2. Zachowaj odpowiedź w pamięci podręcznej.
  3. Zedytuj rekord gdzie indziej.
  4. Nawiguj z powrotem na stronę Users.
  5. Ponownie załóż komponent listy.
  6. React Query automatycznie poprosi o nowe dane.

Brak ręcznej kontroli odświeżania, brak pełnego ładowania strony oraz brak ad-hoc odświeżania ukrytego w obsługownikach nawigacji.

Przed i po

Bez refetchOnMount

Open Users
      ↓
Data Cached
      ↓
Edit User
      ↓
Back to Users
      ↓
Old Cached Data

Z refetchOnMount

Open Users
      ↓
Data Cached
      ↓
Edit User
      ↓
Back to Users
      ↓
Component Mounts
      ↓
Automatic Refetch
      ↓
Fresh Updated Data

Pełny przykład

Zacznij od importu hooka:

import { useQuery } from "@tanstack/react-query";

Komponent lista, który zawsze ponownie waliduje dane przy uruchomieniu:

const Users = () => {
  const { data, isLoading } = useQuery({
    queryKey: ["users"],
    queryFn: fetchUsers,
    refetchOnMount: true,
  });  if (isLoading) {
    return <p>Loading...</p>;
  }  return (
    <div>
      {data?.map((user) => (
        <p key={user.id}>{user.name}</p>
      ))}
    </div>
  );
};

Każde ponowne wejście na tę stronę żąda od serwera najnowszych rekordów zamiast polegać wyłącznie na pamięci podręcznej.

Czy zawsze powinieneś go używać?

Nie. Gdy każda modyfikacja starannie unieważnia powiązane klucze, odświeżanie przy uruchomieniu może być zbędne.

Mimo to jest pomocne w przypadku:

  • Kilku ekranów modyfikujących ten sam zasób.
  • Użytkowników często przechodzących między trasami.
  • Zmian danych poza komponentem, który został uruchomiony.
  • Treści interfejsu muszą być jak najbliższe rzeczywistości serwera.
  • Czasowe dodatkowe wywołania sieci są do przyjęcia.
  • Dla zasobów, które zmieniają się często, włączenie tej flagi to tanie rozwiązanie pozwalające uniknąć wyświetlania przestarzałych danych.

    Gdzie się sprawdza

    Taki model pasuje do narzędzi biurowych z wieloma ekranami, takich jak:

    • Konsole zarządzające kontami i rolami
    • Edytory katalogów produktów
    • Ekrany dotyczące zapasów i magazynu
    • Konsole operatorów wewnętrznych
    • Procesy realizacji zamówień i zakupów
    • Przestrzenie robocze do zarządzania relacjami
    • Huby samousługowe dla pracowników

    Tego typu produkty zazwyczaj edytują jeden zestaw danych poprzez różne ścieżki, dlatego automatyczne ponowne pobieranie danych przy uruchomieniu zapewnia, że widoki list są zgodne z najnowszymi zmianami.

    Ostateczne uwagi

    Kasowanie w pamięci podręcznej to kluczowa zaleta React Query, a ta sama pamięć sprawia, że przestarzałe dane pozostają dostępne po nawigacji. Ustawienie refetchOnMount poleca bibliotece ponowne sprawdzenie serwera za każdym razem, gdy strona jest ponownie ładowana.

    Traktuj to jako zabezpieczenie, a nie zamiennik mechanizmu unieważniania danych. Po dokonaniu modyfikacji, którą sam kontrolujesz, najpierw unieważnij lub zaktualizuj odpowiednie zapytania. Użyj opcji mount refetch w przypadkach, gdy inny ekran, karta lub proces mógł zmienić dane, a Twój lokalny mechanizm obsługi modyfikacji tego nie zauważył.