Es gibt viele Möglichkeiten, Initialdaten für eine Abfrage im Cache bereitzustellen, bevor Sie sie benötigen
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
const result = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
})
const result = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: initialTodos,
})
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
// 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.
// 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.
// 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
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
const result = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: () => getExpensiveTodos(),
})
const result = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/todos'),
initialData: () => getExpensiveTodos(),
})
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
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)
},
})
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.
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,
})
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
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!
},
})
Für einen Vergleich zwischen Initial Data und Placeholder Data siehe die Community Resources.