useQueriesnotifyOnChangeProps akzeptiert nicht mehr "tracked" als WertnotifyOnChangePropsExclusion wurde entferntcancelRefetchonSuccess wird nicht mehr von setQueryData aufgerufenpersistQueryClient und die entsprechenden Persister-Plugins sind nicht mehr experimentell und wurden umbenanntcancel-Methode auf Promises wird nicht mehr unterstütztsetLogger wurde entferntqueryClient, query und mutation entferntsrc/react wurde in src/reactjs umbenanntv4 ist eine Major-Version, daher gibt es einige Breaking Changes zu beachten
Sie müssen Abhängigkeiten deinstallieren/installieren und die Imports ändern
npm uninstall react-query
npm install @tanstack/react-query
npm install @tanstack/react-query-devtools
npm uninstall react-query
npm install @tanstack/react-query
npm install @tanstack/react-query-devtools
- import { useQuery } from 'react-query' // [!code --]
- import { ReactQueryDevtools } from 'react-query/devtools' // [!code --]
+ import { useQuery } from '@tanstack/react-query' // [!code ++]
+ import { ReactQueryDevtools } from '@tanstack/react-query-devtools' // [!code ++]
- import { useQuery } from 'react-query' // [!code --]
- import { ReactQueryDevtools } from 'react-query/devtools' // [!code --]
+ import { useQuery } from '@tanstack/react-query' // [!code ++]
+ import { ReactQueryDevtools } from '@tanstack/react-query-devtools' // [!code ++]
Um die Importmigration zu erleichtern, wird v4 mit einem Codemod geliefert.
Der Codemod ist ein Best-Efforts-Versuch, Ihnen bei der Migration von Breaking Changes zu helfen. Bitte überprüfen Sie den generierten Code gründlich! Außerdem gibt es Randfälle, die der Code-Mod nicht finden kann, also achten Sie bitte auf die Log-Ausgabe.
Sie können ihn einfach mit einem (oder beiden) der folgenden Befehle anwenden
Wenn Sie ihn auf Dateien mit der Endung .js oder .jsx anwenden möchten, verwenden Sie den folgenden Befehl
npx jscodeshift ./path/to/src/ \
--extensions=js,jsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/replace-import-specifier.js
npx jscodeshift ./path/to/src/ \
--extensions=js,jsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/replace-import-specifier.js
Wenn Sie ihn auf Dateien mit der Endung .ts oder .tsx anwenden möchten, verwenden Sie den folgenden Befehl
npx jscodeshift ./path/to/src/ \
--extensions=ts,tsx \
--parser=tsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/replace-import-specifier.js
npx jscodeshift ./path/to/src/ \
--extensions=ts,tsx \
--parser=tsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/replace-import-specifier.js
Bitte beachten Sie, dass Sie im Fall von TypeScript tsx als Parser verwenden müssen, andernfalls wird der Codemod nicht richtig angewendet!
Hinweis: Die Anwendung des Codemods kann Ihre Codeformatierung beeinträchtigen. Vergessen Sie also nicht, prettier und/oder eslint auszuführen, nachdem Sie den Codemod angewendet haben!
Hinweis: Der Codemod ändert *nur* die Imports – das separate Devtools-Paket müssen Sie weiterhin manuell installieren.
In v3 konnten Query- und Mutation-Keys ein String oder ein Array sein. Intern hat React Query immer nur mit Array-Keys gearbeitet, und wir haben dies manchmal an die Konsumenten weitergegeben. Zum Beispiel erhielt man in der queryFn den Key immer als Array, um die Arbeit mit Default Query Functions zu erleichtern.
Dieses Konzept haben wir jedoch nicht auf alle APIs durchgezogen. Zum Beispiel erhielten Sie bei der Verwendung der predicate-Funktion bei Query Filters den rohen Query Key. Das macht die Arbeit mit solchen Funktionen schwierig, wenn Sie Query Keys verwenden, die gemischte Arrays und Strings sind. Dasselbe galt, wenn globale Callbacks verwendet wurden.
Um alle APIs zu vereinheitlichen, haben wir uns entschieden, alle Keys nur noch als Arrays zuzulassen
;-useQuery('todos', fetchTodos) + // [!code --]
useQuery(['todos'], fetchTodos) // [!code ++]
;-useQuery('todos', fetchTodos) + // [!code --]
useQuery(['todos'], fetchTodos) // [!code ++]
Um diese Migration zu erleichtern, haben wir uns entschieden, einen Codemod bereitzustellen.
Der Codemod ist ein Best-Efforts-Versuch, Ihnen bei der Migration von Breaking Changes zu helfen. Bitte überprüfen Sie den generierten Code gründlich! Außerdem gibt es Randfälle, die der Code-Mod nicht finden kann, also achten Sie bitte auf die Log-Ausgabe.
Sie können ihn einfach mit einem (oder beiden) der folgenden Befehle anwenden
Wenn Sie ihn auf Dateien mit der Endung .js oder .jsx anwenden möchten, verwenden Sie den folgenden Befehl
npx jscodeshift ./path/to/src/ \
--extensions=js,jsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/key-transformation.js
npx jscodeshift ./path/to/src/ \
--extensions=js,jsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/key-transformation.js
Wenn Sie ihn auf Dateien mit der Endung .ts oder .tsx anwenden möchten, verwenden Sie den folgenden Befehl
npx jscodeshift ./path/to/src/ \
--extensions=ts,tsx \
--parser=tsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/key-transformation.js
npx jscodeshift ./path/to/src/ \
--extensions=ts,tsx \
--parser=tsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/key-transformation.js
Bitte beachten Sie, dass Sie im Fall von TypeScript tsx als Parser verwenden müssen, andernfalls wird der Codemod nicht richtig angewendet!
Hinweis: Die Anwendung des Codemods kann Ihre Codeformatierung beeinträchtigen. Vergessen Sie also nicht, prettier und/oder eslint auszuführen, nachdem Sie den Codemod angewendet haben!
Mit der Einführung des neuen fetchStatus für eine bessere Offline-Unterstützung wurde der idle-Zustand irrelevant, da fetchStatus: 'idle' denselben Zustand besser erfasst. Weitere Informationen finden Sie unter Why two different states.
Dies betrifft hauptsächlich deaktivierte Queries, die noch keine Daten haben, da diese zuvor im idle-Zustand waren
- status: 'idle' // [!code --]
+ status: 'loading' // [!code ++]
+ fetchStatus: 'idle' // [!code ++]
- status: 'idle' // [!code --]
+ status: 'loading' // [!code ++]
+ fetchStatus: 'idle' // [!code ++]
Werfen Sie auch einen Blick auf den Leitfaden zu abhängigen Queries
Aufgrund dieser Änderung beginnen deaktivierte Queries (auch vorübergehend deaktivierte) im loading-Zustand. Um die Migration zu erleichtern, insbesondere um eine gute Flagge zu haben, um zu wissen, wann ein Lade-Spinner angezeigt werden soll, können Sie isInitialLoading anstelle von isLoading prüfen
;-isLoading + // [!code --]
isInitialLoading // [!code ++]
;-isLoading + // [!code --]
isInitialLoading // [!code ++]
Siehe auch den Leitfaden zum Deaktivieren von Queries
Der Hook useQueries akzeptiert jetzt ein Objekt mit einer queries-Prop als Eingabe. Der Wert der queries-Prop ist ein Array von Queries (dieses Array ist identisch mit dem, was in v3 in useQueries übergeben wurde).
;-useQueries([
{ queryKey1, queryFn1, options1 },
{ queryKey2, queryFn2, options2 },
]) + // [!code --]
useQueries({
queries: [
{ queryKey1, queryFn1, options1 },
{ queryKey2, queryFn2, options2 },
],
}) // [!code ++]
;-useQueries([
{ queryKey1, queryFn1, options1 },
{ queryKey2, queryFn2, options2 },
]) + // [!code --]
useQueries({
queries: [
{ queryKey1, queryFn1, options1 },
{ queryKey2, queryFn2, options2 },
],
}) // [!code ++]
Um das Abbrechen von Updates durch Rückgabe von undefined zu ermöglichen, mussten wir undefined zu einem illegalen Cache-Wert machen. Dies steht im Einklang mit anderen Konzepten von React Query. Zum Beispiel wird durch die Rückgabe von undefined aus der initialData-Funktion ebenfalls *kein* Datum gesetzt.
Darüber hinaus ist es ein einfacher Fehler, Promise<void> zu produzieren, indem man Logging in der Query-Funktion hinzufügt
useQuery(['key'], () =>
axios.get(url).then((result) => console.log(result.data)),
)
useQuery(['key'], () =>
axios.get(url).then((result) => console.log(result.data)),
)
Dies ist jetzt auf Typenebene nicht mehr erlaubt; zur Laufzeit wird undefined in ein *fehlerhaftes Promise* umgewandelt, was bedeutet, dass Sie einen Fehler erhalten, der im Entwicklungsmodus auch auf der Konsole protokolliert wird.
Bitte lesen Sie die Ankündigung neuer Features zu Online-/Offline-Support und auch die dedizierte Seite über Network-Modus
Obwohl React Query ein Async State Manager ist, der für alles verwendet werden kann, das ein Promise erzeugt, wird er am häufigsten für das Abrufen von Daten in Kombination mit Datenabrufbibliotheken verwendet. Deshalb werden standardmäßig Queries und Mutationen pausiert, wenn keine Netzwerkverbindung besteht. Wenn Sie das vorherige Verhalten nutzen möchten, können Sie global networkMode: offlineFirst für Queries und Mutationen einstellen
new QueryClient({
defaultOptions: {
queries: {
networkMode: 'offlineFirst',
},
mutations: {
networkMode: 'offlineFirst',
},
},
})
new QueryClient({
defaultOptions: {
queries: {
networkMode: 'offlineFirst',
},
mutations: {
networkMode: 'offlineFirst',
},
},
})
"tracked" als WertDie Option notifyOnChangeProps akzeptiert keinen "tracked"-Wert mehr. Stattdessen ist useQuery standardmäßig auf das Tracking von Eigenschaften eingestellt. Alle Queries, die notifyOnChangeProps: "tracked" verwenden, sollten aktualisiert werden, indem diese Option entfernt wird.
Wenn Sie dies in einer beliebigen Query umgehen möchten, um das v3-Standardverhalten, nämlich die Neuberechnung bei jeder Änderung einer Query, zu emulieren, akzeptiert notifyOnChangeProps jetzt einen "all"-Wert, um die standardmäßige intelligente Tracking-Optimierung zu deaktivieren.
notifyOnChangePropsExclusion wurde entferntIn v4 ist notifyOnChangeProps standardmäßig auf das Verhalten "tracked" von v3 eingestellt, anstatt auf undefined. Da "tracked" nun das Standardverhalten für v4 ist, macht es keinen Sinn mehr, diese Konfigurationsoption beizubehalten.
Die Option cancelRefetch kann an alle Funktionen übergeben werden, die eine Query imperativ abrufen, nämlich
Mit Ausnahme von fetchNextPage und fetchPreviousPage war dieser Flag standardmäßig false, was inkonsistent und potenziell problematisch war: Das Aufrufen von refetchQueries oder invalidateQueries nach einer Mutation lieferte möglicherweise nicht das aktuellste Ergebnis, wenn ein vorheriger langsamer Fetch bereits lief, da dieser Refetch übersprungen worden wäre.
Wir glauben, dass eine Query, die aktiv von Ihrem Code neu abgerufen wird, standardmäßig den Fetch neu starten sollte.
Deshalb ist dieser Flag jetzt standardmäßig *true* für alle oben genannten Methoden. Das bedeutet auch, dass, wenn Sie refetchQueries zweimal hintereinander aufrufen, ohne auf die Bestätigung zu warten, der erste Fetch nun abgebrochen und mit dem zweiten neu gestartet wird
queryClient.refetchQueries({ queryKey: ['todos'] })
// this will abort the previous refetch and start a new fetch
queryClient.refetchQueries({ queryKey: ['todos'] })
queryClient.refetchQueries({ queryKey: ['todos'] })
// this will abort the previous refetch and start a new fetch
queryClient.refetchQueries({ queryKey: ['todos'] })
Sie können dieses Verhalten umgehen, indem Sie explizit cancelRefetch:false übergeben
queryClient.refetchQueries({ queryKey: ['todos'] })
// this will not abort the previous refetch - it will just be ignored
queryClient.refetchQueries({ queryKey: ['todos'] }, { cancelRefetch: false })
queryClient.refetchQueries({ queryKey: ['todos'] })
// this will not abort the previous refetch - it will just be ignored
queryClient.refetchQueries({ queryKey: ['todos'] }, { cancelRefetch: false })
Hinweis: Es gibt keine Verhaltensänderung für automatisch ausgelöste Fetches, z. B. weil eine Query gemountet wird oder wegen eines Refetchs bei Fensterfokus.
Ein Query-Filter ist ein Objekt mit bestimmten Bedingungen, um eine Query abzugleichen. Historisch gesehen waren die Filteroptionen meist eine Kombination aus booleschen Flags. Die Kombination dieser Flags kann jedoch zu unmöglichen Zuständen führen. Insbesondere
active?: boolean
- When set to true it will match active queries.
- When set to false it will match inactive queries.
inactive?: boolean
- When set to true it will match inactive queries.
- When set to false it will match active queries.
active?: boolean
- When set to true it will match active queries.
- When set to false it will match inactive queries.
inactive?: boolean
- When set to true it will match inactive queries.
- When set to false it will match active queries.
Diese Flags funktionieren nicht gut zusammen, da sie sich gegenseitig ausschließen. Das Setzen von false für beide Flags könnte, basierend auf der Beschreibung, alle Queries abgleichen oder keine Queries, was nicht viel Sinn ergibt.
Mit v4 wurden diese Filter zu einem einzigen Filter kombiniert, um die Absicht besser darzustellen
- active?: boolean // [!code --]
- inactive?: boolean // [!code --]
+ type?: 'active' | 'inactive' | 'all' // [!code ++]
- active?: boolean // [!code --]
- inactive?: boolean // [!code --]
+ type?: 'active' | 'inactive' | 'all' // [!code ++]
Der Filter ist standardmäßig auf all gesetzt, und Sie können wählen, ob Sie nur aktive oder inaktive Queries abgleichen möchten.
queryClient.invalidateQueries hatte zwei zusätzliche, ähnliche Flags
refetchActive: Boolean
- Defaults to true
- When set to false, queries that match the refetch predicate and are actively being rendered
via useQuery and friends will NOT be refetched in the background, and only marked as invalid.
refetchInactive: Boolean
- Defaults to false
- When set to true, queries that match the refetch predicate and are not being rendered
via useQuery and friends will be both marked as invalid and also refetched in the background
refetchActive: Boolean
- Defaults to true
- When set to false, queries that match the refetch predicate and are actively being rendered
via useQuery and friends will NOT be refetched in the background, and only marked as invalid.
refetchInactive: Boolean
- Defaults to false
- When set to true, queries that match the refetch predicate and are not being rendered
via useQuery and friends will be both marked as invalid and also refetched in the background
Aus demselben Grund wurden auch diese kombiniert
- refetchActive?: boolean // [!code --]
- refetchInactive?: boolean // [!code --]
+ refetchType?: 'active' | 'inactive' | 'all' | 'none' // [!code ++]
- refetchActive?: boolean // [!code --]
- refetchInactive?: boolean // [!code --]
+ refetchType?: 'active' | 'inactive' | 'all' | 'none' // [!code ++]
Dieses Flag ist standardmäßig auf active gesetzt, da refetchActive standardmäßig auf true gesetzt war. Das bedeutet, wir brauchen auch eine Möglichkeit, invalidateQueries anzuweisen, gar nicht neu abzurufen, weshalb eine vierte Option (none) hier ebenfalls zulässig ist.
onSuccess wird nicht mehr von setQueryData aufgerufenDies war für viele verwirrend und führte auch zu Endlosschleifen, wenn setQueryData innerhalb von onSuccess aufgerufen wurde. Es war auch eine häufige Fehlerquelle in Kombination mit staleTime, denn wenn Daten nur aus dem Cache gelesen wurden, wurde onSuccess *nicht* aufgerufen.
Ähnlich wie onError und onSettled ist der onSuccess-Callback nun an eine erfolgte Anfrage gebunden. Keine Anfrage -> kein Callback.
Wenn Sie auf Änderungen des data-Feldes hören möchten, können Sie dies am besten mit einem useEffect tun, wobei data Teil des Abhängigkeitsarrays ist. Da React Query stabile Daten durch strukturelles Teilen sicherstellt, wird der Effekt nicht bei jedem Hintergrund-Refetch ausgeführt, sondern nur, wenn sich etwas innerhalb der Daten geändert hat
const { data } = useQuery({ queryKey, queryFn })
React.useEffect(() => mySideEffectHere(data), [data])
const { data } = useQuery({ queryKey, queryFn })
React.useEffect(() => mySideEffectHere(data), [data])
persistQueryClient und die entsprechenden Persister-Plugins sind nicht mehr experimentell und wurden umbenanntDie Plugins createWebStoragePersistor und createAsyncStoragePersistor wurden in createSyncStoragePersister bzw. createAsyncStoragePersistor umbenannt. Die Schnittstelle Persistor in persistQueryClient wurde ebenfalls in Persister umbenannt. Schauen Sie sich diesen Stackexchange-Beitrag an, um die Motivation für diese Änderung zu erfahren.
Da diese Plugins nicht mehr experimentell sind, wurden auch ihre Importpfade aktualisiert
- import { persistQueryClient } from 'react-query/persistQueryClient-experimental' // [!code --]
- import { createWebStoragePersistor } from 'react-query/createWebStoragePersistor-experimental' // [!code --]
- import { createAsyncStoragePersistor } from 'react-query/createAsyncStoragePersistor-experimental' // [!code --]
+ import { persistQueryClient } from '@tanstack/react-query-persist-client' // [!code ++]
+ import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister' // [!code ++]
+ import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister' // [!code ++]
- import { persistQueryClient } from 'react-query/persistQueryClient-experimental' // [!code --]
- import { createWebStoragePersistor } from 'react-query/createWebStoragePersistor-experimental' // [!code --]
- import { createAsyncStoragePersistor } from 'react-query/createAsyncStoragePersistor-experimental' // [!code --]
+ import { persistQueryClient } from '@tanstack/react-query-persist-client' // [!code ++]
+ import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister' // [!code ++]
+ import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister' // [!code ++]
cancel-Methode auf Promises wird nicht mehr unterstütztDie alte cancel-Methode, die es erlaubte, eine cancel-Funktion auf Promises zu definieren, die dann von der Bibliothek zur Unterstützung der Query-Abbrechung verwendet wurde, wurde entfernt. Wir empfehlen die Verwendung der neueren API (eingeführt mit v3.30.0) für die Query-Abbrechung, die intern die AbortController API verwendet und Ihnen eine AbortSignal-Instanz für Ihre Query-Funktion zur Verfügung stellt, um die Query-Abbrechung zu unterstützen.
Types erfordern jetzt TypeScript v4.1 oder höher
Ab v4 ist React Query für moderne Browser optimiert. Wir haben unsere Browserliste aktualisiert, um ein moderneres, performanteres und kleineres Bundle zu erstellen. Sie können die Anforderungen hier lesen.
setLogger wurde entferntEs war möglich, den Logger global zu ändern, indem setLogger aufgerufen wurde. In v4 wird diese Funktion durch ein optionales Feld bei der Erstellung eines QueryClient ersetzt.
- import { QueryClient, setLogger } from 'react-query'; // [!code --]
+ import { QueryClient } from '@tanstack/react-query'; // [!code ++]
- setLogger(customLogger) // [!code --]
- const queryClient = new QueryClient(); // [!code --]
+ const queryClient = new QueryClient({ logger: customLogger }) // [!code ++]
- import { QueryClient, setLogger } from 'react-query'; // [!code --]
+ import { QueryClient } from '@tanstack/react-query'; // [!code ++]
- setLogger(customLogger) // [!code --]
- const queryClient = new QueryClient(); // [!code --]
+ const queryClient = new QueryClient({ logger: customLogger }) // [!code ++]
In v3 hat React Query Query-Ergebnisse standardmäßig 5 Minuten lang zwischengespeichert und dann diese Daten manuell garbage collected. Dieser Standard wurde auch auf serverseitiges React Query angewendet.
Dies führte zu hohem Speicherverbrauch und hängenden Prozessen, die auf diese manuelle Garbage Collection warteten. In v4 ist standardmäßig die serverseitige cacheTime auf Infinity gesetzt, wodurch die manuelle Garbage Collection effektiv deaktiviert wird (der NodeJS-Prozess wird alles bereinigen, sobald eine Anfrage abgeschlossen ist).
Diese Änderung betrifft nur Benutzer von serverseitigem React Query, z. B. mit Next.js. Wenn Sie eine cacheTime manuell setzen, wird dies Sie nicht beeinträchtigen (obwohl Sie vielleicht ein ähnliches Verhalten wünschen).
Ab v4 protokolliert React Query keine Fehler (z. B. fehlgeschlagene Fetches) mehr auf der Konsole im Produktionsmodus, da dies für viele verwirrend war. Fehler werden im Entwicklungsmodus weiterhin angezeigt.
React Query unterstützt jetzt package.json "exports" und ist vollständig kompatibel mit der nativen Auflösung von Node für CommonJS und ESM. Wir gehen nicht davon aus, dass dies für die meisten Benutzer eine Breaking Change darstellt, aber es beschränkt die Dateien, die Sie in Ihr Projekt importieren können, auf die von uns offiziell unterstützten Einstiegspunkte.
Das manuelle Abonnieren des QueryCache lieferte schon immer ein QueryCacheNotifyEvent, aber das war nicht der Fall für den MutationCache. Wir haben das Verhalten vereinheitlicht und auch die Ereignisnamen entsprechend angepasst.
- type: 'queryAdded' // [!code --]
+ type: 'added' // [!code ++]
- type: 'queryRemoved' // [!code --]
+ type: 'removed' // [!code ++]
- type: 'queryUpdated' // [!code --]
+ type: 'updated' // [!code ++]
- type: 'queryAdded' // [!code --]
+ type: 'added' // [!code ++]
- type: 'queryRemoved' // [!code --]
+ type: 'removed' // [!code ++]
- type: 'queryUpdated' // [!code --]
+ type: 'updated' // [!code ++]
Der MutationCacheNotifyEvent verwendet dieselben Typen wie der QueryCacheNotifyEvent.
Hinweis: Dies ist nur relevant, wenn Sie die Caches manuell über queryCache.subscribe oder mutationCache.subscribe abonnieren
Mit Version 3.22.0 wurden die Hydration-Utilities in den React Query Core verschoben. Mit v3 konnten Sie noch die alten Exporte aus react-query/hydration verwenden, aber diese Exporte wurden mit v4 entfernt.
- import { dehydrate, hydrate, useHydrate, Hydrate } from 'react-query/hydration' // [!code --]
+ import { dehydrate, hydrate, useHydrate, Hydrate } from '@tanstack/react-query' // [!code ++]
- import { dehydrate, hydrate, useHydrate, Hydrate } from 'react-query/hydration' // [!code --]
+ import { dehydrate, hydrate, useHydrate, Hydrate } from '@tanstack/react-query' // [!code ++]
queryClient, query und mutation entferntDie Methoden cancelMutations und executeMutation auf dem QueryClient waren undokumentiert und intern ungenutzt, daher haben wir sie entfernt. Da es sich nur um einen Wrapper um eine Methode handelte, die auf dem mutationCache verfügbar war, können Sie die Funktionalität von executeMutation weiterhin nutzen
- executeMutation< // [!code --]
- TData = unknown, // [!code --]
- TError = unknown, // [!code --]
- TVariables = void, // [!code --]
- TContext = unknown // [!code --]
- >( // [!code --]
- options: MutationOptions<TData, TError, TVariables, TContext> // [!code --]
- ): Promise<TData> { // [!code --]
- return this.mutationCache.build(this, options).execute() // [!code --]
- } // [!code --]
- executeMutation< // [!code --]
- TData = unknown, // [!code --]
- TError = unknown, // [!code --]
- TVariables = void, // [!code --]
- TContext = unknown // [!code --]
- >( // [!code --]
- options: MutationOptions<TData, TError, TVariables, TContext> // [!code --]
- ): Promise<TData> { // [!code --]
- return this.mutationCache.build(this, options).execute() // [!code --]
- } // [!code --]
Zusätzlich wurde query.setDefaultOptions entfernt, da es ebenfalls ungenutzt war. mutation.cancel wurde entfernt, da es die ausgehende Anfrage nicht tatsächlich abbrach.
src/react wurde in src/reactjs umbenanntZuvor hatte React Query ein Verzeichnis namens react, das aus dem Modul react importierte. Dies konnte zu Problemen bei einigen Jest-Konfigurationen führen, was zu Fehlern bei der Ausführung von Tests wie
TypeError: Cannot read property 'createContext' of undefined
TypeError: Cannot read property 'createContext' of undefined
Mit dem umbenannten Verzeichnis ist dies kein Problem mehr.
Wenn Sie etwas direkt aus 'react-query/react' in Ihr Projekt importiert haben (im Gegensatz zu nur 'react-query'), müssen Sie Ihre Imports aktualisieren
- import { QueryClientProvider } from 'react-query/react'; // [!code --]
+ import { QueryClientProvider } from '@tanstack/react-query/reactjs'; // [!code ++]
- import { QueryClientProvider } from 'react-query/react'; // [!code --]
+ import { QueryClientProvider } from '@tanstack/react-query/reactjs'; // [!code ++]
v4 kommt mit einer beeindruckenden Reihe neuer Features
React 18 wurde Anfang des Jahres veröffentlicht, und v4 unterstützt es nun erstklassig und die neuen Concurrent-Features, die es mitbringt.
In v3 hat React Query immer Queries und Mutationen gestartet, aber dann angenommen, dass Sie bei einem erneuten Versuch eine Internetverbindung benötigen. Dies hat zu mehreren verwirrenden Situationen geführt
Mit v4 führt React Query einen neuen networkMode ein, um all diese Probleme zu lösen. Bitte lesen Sie die dedizierte Seite über den neuen Network-Modus für weitere Informationen.
React Query nutzt standardmäßig das "Tracking" von Query-Eigenschaften, was zu einer deutlichen Verbesserung der Render-Optimierung führen sollte. Diese Funktion existiert bereits seit v3.6.0 und ist nun mit v4 das Standardverhalten.
Bei Verwendung der funktionalen Updater-Form von setQueryData können Sie jetzt das Update abbrechen, indem Sie undefined zurückgeben. Dies ist hilfreich, wenn undefined Ihnen als previousValue übergeben wird, was bedeutet, dass derzeit kein gecachter Eintrag vorhanden ist und Sie keinen erstellen möchten/können, wie im Beispiel des Toggle eines Todos
queryClient.setQueryData(['todo', id], (previousTodo) =>
previousTodo ? { ...previousTodo, done: true } : undefined,
)
queryClient.setQueryData(['todo', id], (previousTodo) =>
previousTodo ? { ...previousTodo, done: true } : undefined,
)
Mutationen können jetzt auch automatisch garbage collected werden, genau wie Queries. Die Standard- cacheTime für Mutationen ist ebenfalls auf 5 Minuten eingestellt.
Benutzerdefinierte Kontexte können jetzt angegeben werden, um Hooks mit ihrem passenden Provider zu koppeln. Dies ist entscheidend, wenn es mehrere React Query Provider-Instanzen im Komponentenbaum geben kann und Sie sicherstellen müssen, dass Ihr Hook die richtige Provider-Instanz verwendet.
Ein Beispiel
// Our first data package: @my-scope/container-data
const context = React.createContext<QueryClient | undefined>(undefined)
const queryClient = new QueryClient()
export const useUser = () => {
return useQuery(USER_KEY, USER_FETCHER, {
context,
})
}
export const ContainerDataProvider = ({
children,
}: {
children: React.ReactNode
}) => {
return (
<QueryClientProvider client={queryClient} context={context}>
{children}
</QueryClientProvider>
)
}
// Our first data package: @my-scope/container-data
const context = React.createContext<QueryClient | undefined>(undefined)
const queryClient = new QueryClient()
export const useUser = () => {
return useQuery(USER_KEY, USER_FETCHER, {
context,
})
}
export const ContainerDataProvider = ({
children,
}: {
children: React.ReactNode
}) => {
return (
<QueryClientProvider client={queryClient} context={context}>
{children}
</QueryClientProvider>
)
}
// Our second data package: @my-scope/my-component-data
const context = React.createContext<QueryClient | undefined>(undefined)
const queryClient = new QueryClient()
export const useItems = () => {
return useQuery(ITEMS_KEY, ITEMS_FETCHER, {
context,
})
}
export const MyComponentDataProvider = ({
children,
}: {
children: React.ReactNode
}) => {
return (
<QueryClientProvider client={queryClient} context={context}>
{children}
</QueryClientProvider>
)
}
// Our second data package: @my-scope/my-component-data
const context = React.createContext<QueryClient | undefined>(undefined)
const queryClient = new QueryClient()
export const useItems = () => {
return useQuery(ITEMS_KEY, ITEMS_FETCHER, {
context,
})
}
export const MyComponentDataProvider = ({
children,
}: {
children: React.ReactNode
}) => {
return (
<QueryClientProvider client={queryClient} context={context}>
{children}
</QueryClientProvider>
)
}
// Our application
import { ContainerDataProvider, useUser } from "@my-scope/container-data";
import { AppDataProvider } from "@my-scope/app-data";
import { MyComponentDataProvider, useItems } from "@my-scope/my-component-data";
<ContainerDataProvider> // <-- Provides container data (like "user") using its own React Query provider
...
<AppDataProvider> // <-- Provides app data using its own React Query provider (unused in this example)
...
<MyComponentDataProvider> // <-- Provides component data (like "items") using its own React Query provider
<MyComponent />
</MyComponentDataProvider>
...
</AppDataProvider>
...
</ContainerDataProvider>
// Example of hooks provided by the "DataProvider" components above:
const MyComponent = () => {
const user = useUser() // <-- Uses the context specified in ContainerDataProvider.
const items = useItems() // <-- Uses the context specified in MyComponentDataProvider
...
}
// Our application
import { ContainerDataProvider, useUser } from "@my-scope/container-data";
import { AppDataProvider } from "@my-scope/app-data";
import { MyComponentDataProvider, useItems } from "@my-scope/my-component-data";
<ContainerDataProvider> // <-- Provides container data (like "user") using its own React Query provider
...
<AppDataProvider> // <-- Provides app data using its own React Query provider (unused in this example)
...
<MyComponentDataProvider> // <-- Provides component data (like "items") using its own React Query provider
<MyComponent />
</MyComponentDataProvider>
...
</AppDataProvider>
...
</ContainerDataProvider>
// Example of hooks provided by the "DataProvider" components above:
const MyComponent = () => {
const user = useUser() // <-- Uses the context specified in ContainerDataProvider.
const items = useItems() // <-- Uses the context specified in MyComponentDataProvider
...
}