Framework
Version

Anfängliche Query-Daten

Es gibt viele Möglichkeiten, Initialdaten für eine Abfrage im Cache bereitzustellen, bevor Sie sie benötigen

Verwendung von initialData zum Vorabfüllen einer Abfrage

Es kann vorkommen, dass Sie die Initialdaten für eine Abfrage bereits in Ihrer Anwendung verfügbar haben und diese einfach direkt an Ihre Abfrage übergeben können. Wenn dies der Fall ist, können Sie die Option config.initialData verwenden, um die Initialdaten für eine Abfrage festzulegen und den anfänglichen Ladestatus zu überspringen!

WICHTIG: initialData wird im Cache gespeichert, daher wird nicht empfohlen, Platzhalter-, Teil- oder unvollständige Daten für diese Option bereitzustellen, sondern stattdessen placeholderData zu verwenden

tsx
const result = useQuery(() => {
  queryKey: ['todos'],
  queryFn: () => fetch('/todos'),
  initialData: initialTodos,
})
const result = useQuery(() => {
  queryKey: ['todos'],
  queryFn: () => fetch('/todos'),
  initialData: initialTodos,
})

staleTime und initialDataUpdatedAt

Standardmäßig werden initialData als völlig frisch behandelt, als wären sie gerade erst abgerufen worden. Dies bedeutet auch, dass sie beeinflusst, wie sie von der Option staleTime interpretiert werden.

  • Wenn Sie Ihren Query Observer mit initialData und ohne staleTime (Standard staleTime: 0) konfigurieren, wird die Abfrage beim ersten Mount sofort neu abgerufen

    tsx
    // Will show initialTodos immediately, but also immediately refetch todos after mount
    const result = useQuery(() => {
      queryKey: ['todos'],
      queryFn: () => fetch('/todos'),
      initialData: initialTodos,
    })
    
    // Will show initialTodos immediately, but also immediately refetch todos after mount
    const result = useQuery(() => {
      queryKey: ['todos'],
      queryFn: () => fetch('/todos'),
      initialData: initialTodos,
    })
    
  • Wenn Sie Ihren Query Observer mit initialData und einer staleTime von 1000 ms konfigurieren, gelten die Daten für diesen Zeitraum als frisch, als wären sie gerade aus Ihrer Abfragefunktion abgerufen worden.

    tsx
    // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
    const result = useQuery(() => {
      queryKey: ['todos'],
      queryFn: () => fetch('/todos'),
      initialData: initialTodos,
      staleTime: 1000,
    })
    
    // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
    const result = useQuery(() => {
      queryKey: ['todos'],
      queryFn: () => fetch('/todos'),
      initialData: initialTodos,
      staleTime: 1000,
    })
    
  • Was ist, wenn Ihre initialData nicht ganz frisch sind? Das bringt uns zur letzten Konfiguration, die tatsächlich am genauesten ist und eine Option namens initialDataUpdatedAt verwendet. Diese Option ermöglicht es Ihnen, einen numerischen JS-Zeitstempel in Millisekunden zu übergeben, wann die initialData selbst zuletzt aktualisiert wurde, z. B. was Date.now() liefert. Beachten Sie, dass Sie bei einem Unix-Zeitstempel diesen in einen JS-Zeitstempel umwandeln müssen, indem Sie ihn mit 1000 multiplizieren.

    tsx
    // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
    const result = useQuery(() => {
      queryKey: ['todos'],
      queryFn: () => fetch('/todos'),
      initialData: initialTodos,
      staleTime: 60 * 1000, // 1 minute
      // This could be 10 seconds ago or 10 minutes ago
      initialDataUpdatedAt: initialTodosUpdatedTimestamp, // eg. 1608412420052
    })
    
    // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
    const result = useQuery(() => {
      queryKey: ['todos'],
      queryFn: () => fetch('/todos'),
      initialData: initialTodos,
      staleTime: 60 * 1000, // 1 minute
      // This could be 10 seconds ago or 10 minutes ago
      initialDataUpdatedAt: initialTodosUpdatedTimestamp, // eg. 1608412420052
    })
    

    Diese Option ermöglicht es der staleTime, für ihren ursprünglichen Zweck verwendet zu werden, nämlich zu bestimmen, wie frisch die Daten sein müssen, während gleichzeitig die Daten beim Mount neu abgerufen werden können, wenn die initialData älter als die staleTime sind. Im obigen Beispiel müssen unsere Daten innerhalb von 1 Minute frisch sein, und wir können der Abfrage einen Hinweis darauf geben, wann die initialData zuletzt aktualisiert wurden, damit die Abfrage selbst entscheiden kann, ob die Daten erneut abgerufen werden müssen oder nicht.

    Wenn Sie Ihre Daten lieber als vorab abgerufene Daten behandeln möchten, empfehlen wir Ihnen, die APIs prefetchQuery oder fetchQuery zu verwenden, um den Cache vorab zu füllen. Dadurch können Sie Ihre staleTime unabhängig von Ihren initialData konfigurieren

Initial Data Function

Wenn der Prozess zum Abrufen der Initialdaten einer Abfrage intensiv ist oder Sie ihn nicht bei jedem Render ausführen möchten, können Sie eine Funktion als Wert für initialData übergeben. Diese Funktion wird nur einmal ausgeführt, wenn die Abfrage initialisiert wird, und spart Ihnen wertvollen Speicher und/oder CPU

tsx
const result = useQuery(() => {
  queryKey: ['todos'],
  queryFn: () => fetch('/todos'),
  initialData: () => getExpensiveTodos(),
})
const result = useQuery(() => {
  queryKey: ['todos'],
  queryFn: () => fetch('/todos'),
  initialData: () => getExpensiveTodos(),
})

Initial Data aus dem Cache

Unter bestimmten Umständen können Sie die Initialdaten für eine Abfrage aus dem zwischengespeicherten Ergebnis einer anderen Abfrage bereitstellen. Ein gutes Beispiel dafür wäre, die zwischengespeicherten Daten einer Todos-Listenabfrage nach einem einzelnen Todo-Element zu durchsuchen und dieses dann als Initialdaten für Ihre individuelle Todo-Abfrage zu verwenden

tsx
const result = useQuery(() => {
  queryKey: ['todo', todoId],
  queryFn: () => fetch('/todos'),
  initialData: () => {
    // Use a todo from the 'todos' query as the initial data for this todo query
    return queryClient.getQueryData(['todos'])?.find((d) => d.id === todoId)
  },
})
const result = useQuery(() => {
  queryKey: ['todo', todoId],
  queryFn: () => fetch('/todos'),
  initialData: () => {
    // Use a todo from the 'todos' query as the initial data for this todo query
    return queryClient.getQueryData(['todos'])?.find((d) => d.id === todoId)
  },
})

Initial Data aus dem Cache mit initialDataUpdatedAt

Das Abrufen von Initialdaten aus dem Cache bedeutet, dass die Quellabfrage, die Sie zum Nachschlagen der Initialdaten verwenden, wahrscheinlich alt ist. Anstatt eine künstliche staleTime zu verwenden, um zu verhindern, dass Ihre Abfrage sofort neu abgerufen wird, wird empfohlen, die dataUpdatedAt der Quellabfrage an initialDataUpdatedAt zu übergeben. Dies versorgt die Abfrageinstanz mit allen Informationen, die sie benötigt, um zu bestimmen, ob und wann die Abfrage neu abgerufen werden muss, unabhängig davon, ob Initialdaten bereitgestellt wurden.

tsx
const result = useQuery(() => {
  queryKey: ['todos', todoId],
  queryFn: () => fetch(`/todos/${todoId}`),
  initialData: () =>
    queryClient.getQueryData(['todos'])?.find((d) => d.id === todoId),
  initialDataUpdatedAt: () =>
    queryClient.getQueryState(['todos'])?.dataUpdatedAt,
})
const result = useQuery(() => {
  queryKey: ['todos', todoId],
  queryFn: () => fetch(`/todos/${todoId}`),
  initialData: () =>
    queryClient.getQueryData(['todos'])?.find((d) => d.id === todoId),
  initialDataUpdatedAt: () =>
    queryClient.getQueryState(['todos'])?.dataUpdatedAt,
})

Bedingtes Initial Data aus dem Cache

Wenn die Quellabfrage, die Sie zum Nachschlagen der Initialdaten verwenden, alt ist, möchten Sie die zwischengespeicherten Daten möglicherweise überhaupt nicht verwenden und einfach vom Server abrufen. Um diese Entscheidung zu erleichtern, können Sie stattdessen die Methode queryClient.getQueryState verwenden, um mehr Informationen über die Quellabfrage zu erhalten, einschließlich eines Zeitstempels state.dataUpdatedAt, den Sie verwenden können, um zu entscheiden, ob die Abfrage "frisch" genug für Ihre Bedürfnisse ist

tsx
const result = useQuery(() => {
  queryKey: ['todo', todoId],
  queryFn: () => fetch(`/todos/${todoId}`),
  initialData: () => {
    // Get the query state
    const state = queryClient.getQueryState(['todos'])

    // If the query exists and has data that is no older than 10 seconds...
    if (state && Date.now() - state.dataUpdatedAt <= 10 * 1000) {
      // return the individual todo
      return state.data.find((d) => d.id === todoId)
    }

    // Otherwise, return undefined and let it fetch from a hard loading state!
  },
})
const result = useQuery(() => {
  queryKey: ['todo', todoId],
  queryFn: () => fetch(`/todos/${todoId}`),
  initialData: () => {
    // Get the query state
    const state = queryClient.getQueryState(['todos'])

    // If the query exists and has data that is no older than 10 seconds...
    if (state && Date.now() - state.dataUpdatedAt <= 10 * 1000) {
      // return the individual todo
      return state.data.find((d) => d.id === todoId)
    }

    // Otherwise, return undefined and let it fetch from a hard loading state!
  },
})

Weiterführende Lektüre

Für einen Vergleich zwischen Initial Data und Placeholder Data, schauen Sie sich die Community Resources an.