### Install @tanstack/query-core with yarn Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/introduction/getting-started.md Use this command to install the core package with yarn. ```bash yarn add @tanstack/query-core {packageJson.name} ``` -------------------------------- ### Install @tanstack/query-core with npm Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/introduction/getting-started.md Use this command to install the core package with npm. ```bash npm install @tanstack/query-core {packageJson.name} ``` -------------------------------- ### Manual Control with `start()` Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Shows how to disable a query by default and trigger it manually using the `start()` method, allowing for control over when data fetching occurs. ```APIDOC ## Query — Manual control with `start()` Disable a query by default and trigger it manually with new query parameters. ```ts import { Query } from "mobx-tanstack-query"; const petQuery = new Query({ queryClient, queryKey: ["pets", undefined as string | undefined] as const, enabled: false, queryFn: async ({ queryKey, signal }) => { const res = await fetch(`/api/pets/${queryKey[1]}`, { signal }); return res.json() as Promise; }, }); // Trigger manually with updated key const result = await petQuery.start({ queryKey: ["pets", "Fluffy"], }); console.log(result.data); // Pet { name: "Fluffy", ... } ``` ``` -------------------------------- ### Install @tanstack/query-core with pnpm Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/introduction/getting-started.md Use this command to install the core package with pnpm. ```bash pnpm add @tanstack/query-core {packageJson.name} ``` -------------------------------- ### Install MobX Tanstack Query Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Install the necessary packages for MobX Tanstack Query using npm, pnpm, or yarn. ```bash # npm npm install @tanstack/query-core mobx-tanstack-query # pnpm pnpm add @tanstack/query-core mobx-tanstack-query # yarn yarn add @tanstack/query-core mobx-tanstack-query ``` -------------------------------- ### Manual Control of Query Fetching Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Illustrates how to manually trigger query data fetching using the 'start' method. ```APIDOC ## Manual control of query fetching This approach is suitable when we need to manually load data using a query. Example: ```ts import { Query } from "@mobx-tanstack/query"; // Assume queryClient and petsApi are defined elsewhere // const queryClient = new QueryClient(); // const petsApi = { getPetByName: async (name: string) => ({ json: async () => ({ id: 1, name }) }) }; const petQuery = new Query({ queryClient, queryKey: ["pets", undefined as string | undefined] as const, enabled: false, queryFn: async ({ queryKey }) => { const petName = queryKey[1]!; const response = await petsApi.getPetByName(petName); return await response.json(); }, }); const result = await petQuery.start({ queryKey: ["pets", "Fluffy"], }); console.log(result.data); ``` ``` -------------------------------- ### Manual Query Control with start() Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Manually trigger a query with new parameters by disabling it initially and using the `start()` method. Requires `queryClient` to be initialized. ```typescript import { Query } from "mobx-tanstack-query"; const petQuery = new Query({ queryClient, queryKey: ["pets", undefined as string | undefined] as const, enabled: false, queryFn: async ({ queryKey, signal }) => { const res = await fetch(`/api/pets/${queryKey[1]}`, { signal }); return res.json() as Promise; }, }); // Trigger manually with updated key const result = await petQuery.start({ queryKey: ["pets", "Fluffy"], }); console.log(result.data); // Pet { name: "Fluffy", ... } ``` -------------------------------- ### Install Persister Dependencies Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/QueryClient.md Install the required packages for TanStack Query persistence using npm, pnpm, or yarn. ```bash npm install @tanstack/query-async-storage-persister @tanstack/react-query-persist-client ``` ```bash pnpm add @tanstack/query-async-storage-persister @tanstack/react-query-persist-client ``` ```bash yarn add @tanstack/query-async-storage-persister @tanstack/react-query-persist-client ``` -------------------------------- ### Basic Usage Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Demonstrates the fundamental setup of a Query instance, making its state properties (like isLoading, data) MobX observables for automatic UI updates. ```APIDOC ## Query MobX-reactive class wrapping a Tanstack Query observer. All result fields (`data`, `isLoading`, `isError`, `status`, etc.) are MobX observables that automatically trigger reactions and re-renders. ```ts import { Query } from "mobx-tanstack-query"; import { observable, reaction, action } from "mobx"; import { observer } from "mobx-react-lite"; // --- Basic usage --- const petsQuery = new Query({ queryClient, queryKey: ["pets"], queryFn: async ({ signal }) => { const response = await fetch("/api/pets", { signal }); if (!response.ok) throw response; return response.json() as Promise; }, }); console.log(petsQuery.isLoading); // true initially console.log(petsQuery.data); // undefined initially reaction( () => petsQuery.isLoading, (isLoading) => console.log("Loading:", isLoading), ); // --- Dynamic queryKey and enabled (MobX-tracked) --- const petName = observable.box(undefined); const petQuery = new Query({ queryClient, queryKey: () => ["pets", petName.get()] as const, enabled: ({ queryKey }) => !!queryKey[1], queryFn: async ({ queryKey, signal }) => { const response = await fetch(`/api/pets/${queryKey[1]}`, { signal }); return response.json() as Promise; }, }); petName.set("Fluffy"); // query automatically starts fetching // --- Inside a MobX class with lifecycle management --- class PetViewModel { abortController = new AbortController(); @observable accessor selectedPet = "Fluffy"; petQuery = new Query({ queryClient, abortSignal: this.abortController.signal, // auto-destroy on abort queryFn: async ({ queryKey, signal }) => { const res = await fetch(`/api/pets/${queryKey[1]}`, { signal }); return res.json() as Promise; }, options: () => ({ queryKey: ["pets", this.selectedPet] as const, enabled: !!this.selectedPet, }), onDone: (data) => console.log("Loaded:", data), onError: (err) => console.error("Failed:", err), }); @action setSelectedPet(name: string) { this.selectedPet = name; } destroy() { this.abortController.abort(); // cleans up query automatically } } // --- React component --- const PetList = observer(() => { if (petsQuery.isLoading) return
Loading...
; if (petsQuery.isError) return
Error: {String(petsQuery.error)}
; return
    {petsQuery.data?.map(p =>
  • {p.name}
  • )}
; }); ``` ``` -------------------------------- ### Write Your First Query Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/introduction/getting-started.md Define a new Query instance to fetch data. This example fetches fruit data based on a query key and uses a custom fetch function. ```typescript import { Query } from "mobx-tanstack-query"; const fruitQuery = new Query({ queryClient, queryFn: async ({ queryKey }) => { const response = await fetch(`/api/fruits/${queryKey[1]}`); return await response.json(); }, queryKey: ["fruits", "apple"], }); ``` -------------------------------- ### start(params) Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Enable the query if it is disabled and then fetch the query data. This method provides manual control over query fetching. ```APIDOC ## `start(params)` ### Description Enable the query if it is disabled and then fetch the query data. This method provides manual control over query fetching. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```ts const query = new Query({ queryClient, queryKey: ["pets", undefined as string | undefined] as const, enabled: false, queryFn: async ({ queryKey }) => { const petName = queryKey[1]!; const response = await petsApi.getPetByName(petName); return await response.json(); }, }); // Manually start the query const result = await query.start({ queryKey: ["pets", "Fluffy"], }); console.log(result.data); ``` ### Response #### Success Response (200) - **data** (any) - The fetched data. #### Response Example ```json { "data": "example data" } ``` ``` -------------------------------- ### Manually Start Query with start Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Enables a disabled query and initiates a fetch. This method is useful for manual control over query execution. It accepts query key parameters to specify which query to start. The result of the fetch is returned. ```typescript const query = new Query({ queryClient, queryKey: ["pets", undefined as string | undefined] as const, enabled: false, queryFn: async ({ queryKey }) => { const petName = queryKey[1]!; const response = await petsApi.getPetByName(petName); return await response.json(); }, }); // Manually start the query const result = await query.start({ queryKey: ["pets", "Fluffy"], }); console.log(result.data); ``` -------------------------------- ### Basic Query Usage with MobX Reactivity Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Demonstrates basic MobX-TanStack-Query setup. All result fields are MobX observables that trigger reactions automatically. Ensure `queryClient` is initialized. ```typescript import { Query } from "mobx-tanstack-query"; import { observable, reaction, action } from "mobx"; import { observer } from "mobx-react-lite"; // --- Basic usage --- const petsQuery = new Query({ queryClient, queryKey: ["pets"], queryFn: async ({ signal }) => { const response = await fetch("/api/pets", { signal }); if (!response.ok) throw response; return response.json() as Promise; }, }); console.log(petsQuery.isLoading); // true initially console.log(petsQuery.data); // undefined initially reaction( () => petsQuery.isLoading, (isLoading) => console.log("Loading:", isLoading), ); // --- Dynamic queryKey and enabled (MobX-tracked) --- const petName = observable.box(undefined); const petQuery = new Query({ queryClient, queryKey: () => ["pets", petName.get()] as const, enabled: ({ queryKey }) => !!queryKey[1], queryFn: async ({ queryKey, signal }) => { const response = await fetch(`/api/pets/${queryKey[1]}`, { signal }); return response.json() as Promise; }, }); petName.set("Fluffy"); // query automatically starts fetching // --- Inside a MobX class with lifecycle management --- class PetViewModel { abortController = new AbortController(); @observable accessor selectedPet = "Fluffy"; petQuery = new Query({ queryClient, abortSignal: this.abortController.signal, // auto-destroy on abort queryFn: async ({ queryKey, signal }) => { const res = await fetch(`/api/pets/${queryKey[1]}`, { signal }); return res.json() as Promise; }, options: () => ({ queryKey: ["pets", this.selectedPet] as const, enabled: !!this.selectedPet, }), onDone: (data) => console.log("Loaded:", data), onError: (err) => console.error("Failed:", err), }); @action setSelectedPet(name: string) { this.selectedPet = name; } destroy() { this.abortController.abort(); // cleans up query automatically } } // --- React component --- const PetList = observer(() => { if (petsQuery.isLoading) return
Loading...
; if (petsQuery.isError) return
Error: {String(petsQuery.error)}
; return
    {petsQuery.data?.map(p =>
  • {p.name}
  • )}
; }); ``` -------------------------------- ### Configuring Query Features Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/QueryClient.md Example of initializing QueryClient with specific configurations for queries, such as enabling lazy loading and error handling. ```typescript export const queryClient = new QueryClient({ defaultOptions: { queries: { lazy: true, // lazyDelay: 300, enableOnDemand: true, // resetOnDestroy: false, // dynamicOptionsUpdateDelay: undefined, throwOnError: true, refetchOnWindowFocus: false, refetchOnReconnect: false, staleTime: 0, retry: false, // transformError: (error) => error, }, }, }); ``` -------------------------------- ### Configuring Mutation Features Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/QueryClient.md Example of initializing QueryClient with specific configurations for mutations, including lazy loading and invalidation by key. ```typescript export const queryClient = new QueryClient({ defaultOptions: { mutations: { // invalidateByKey: true, // resetOnDestroy: true, lazy: true, // lazyDelay: 300, // transformError: (error) => error, }, }, }); ``` -------------------------------- ### Create Query and Mutation with Preset API Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/preset/index.md Use createQuery and createMutation from the preset to automatically mount the QueryClient. Call start() on the query and mutate() on the mutation to initiate them. The mutation can invalidate the query upon completion. ```typescript import { createQuery, createMutation } from "mobx-tanstack-query/preset"; const query = createQuery(async ({ signal }) => { const response = await fetch('/fruits', { signal }); return await response.json(); }, { enabled: false, queryKey: ['fruits'] }); await query.start(); const mutation = createMutation(async (fruitName: string) => { await fetch('/fruits', { method: "POST", data: { fruitName } }) }, { onDone: () => { query.invalidate(); } }); await mutation.mutate('Apple'); ``` -------------------------------- ### Initialize InfiniteQuery with MobX Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/InfiniteQuery.md Create an instance of InfiniteQuery by providing essential parameters like queryClient, queryKey, queryFn, initialPageParam, onError, and getNextPageParam. This setup is used for fetching paginated data with MobX reactivity. ```typescript const query = new InfiniteQuery({ queryClient, abortSignal: this.abortSignal, queryKey: ['stars'] queryFn: async ({ signal, pageParam }) => { const response = await starsApi.fetchStarsList( { count: 20, page: pageParam, }, { signal, }, ); return response.data; }, initialPageParam: 1, onError: (e) => { notify({ type: 'danger', title: 'Failed to load stars', }); }, getNextPageParam: (lastPage, _, lastPageParam) => { return lastPage.length ? lastPageParam + 1 : null; }, }); ``` -------------------------------- ### Manual Query Fetching Control Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Suitable for scenarios requiring manual data loading. The query is initialized with 'enabled: false' and can be started explicitly using the 'start' method. ```typescript const petQuery = new Query({ queryClient, queryKey: ["pets", undefined as string | undefined] as const, enabled: false, queryFn: async ({ queryKey }) => { const petName = queryKey[1]!; const response = await petsApi.getPetByName(petName); return await response.json(); }, }); const result = await petQuery.start({ queryKey: ["pets", "Fluffy"], }); console.log(result.data); ``` -------------------------------- ### createInfiniteQuery Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Factory function from `mobx-tanstack-query/preset` for paginated queries using the preset `QueryClient`. It streamlines the setup of infinite scrolling or paginated data fetching. ```APIDOC ## Preset API — `createInfiniteQuery` Factory function from `mobx-tanstack-query/preset` for paginated queries using the preset `QueryClient`. ```ts import { createInfiniteQuery } from "mobx-tanstack-query/preset"; const petsInfiniteQuery = createInfiniteQuery( async ({ signal, queryKey, pageParam }) => { const response = await fetch( `/api/pets?page=${pageParam}&limit=10`, { signal }, ); return response.json() as Promise; }, { queryKey: ["pets", "infinite"], initialPageParam: 1, getNextPageParam: (lastPage, _allPages, lastPageParam) => { return lastPage.length === 10 ? lastPageParam + 1 : null; }, }, ); await petsInfiniteQuery.fetchNextPage(); console.log(petsInfiniteQuery.data?.pages.flat()); // Pet[] console.log(petsInfiniteQuery.hasNextPage); // boolean ``` ``` -------------------------------- ### createQuery Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Factory function from `mobx-tanstack-query/preset` that creates a `Query` with a pre-configured `QueryClient`. It automatically calls `mount()` once per client instance, simplifying query setup. ```APIDOC ## Preset API — `createQuery` Factory function from `mobx-tanstack-query/preset` that creates a `Query` with a pre-configured `QueryClient`, automatically calling `mount()` once per client instance. ```ts import { createQuery } from "mobx-tanstack-query/preset"; // Shorthand: pass queryFn first, then options const petsQuery = createQuery( async ({ signal, queryKey }) => { const response = await fetch(`/api/pets`, { signal }); return response.json() as Promise; }, { queryKey: ["pets"], staleTime: 60_000, }, ); console.log(petsQuery.isLoading); // true console.log(petsQuery.data); // undefined → Pet[] once resolved // Dynamic options with observable state import { observable } from "mobx"; const filter = observable.box("active"); const filteredPetsQuery = createQuery( async ({ queryKey, signal }) => { const res = await fetch(`/api/pets?status=${queryKey[1]}`, { signal }); return res.json(); }, { queryKey: () => ["pets", filter.get()] as const, enabled: ({ queryKey }) => !!queryKey[1], }, ); filter.set("inactive"); // query automatically re-runs with new key ``` ``` -------------------------------- ### Enable On-Demand Fetching with MobX Query Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Use `enableOnDemand: true` to defer fetching until `.data` is accessed. The fetch starts only when the data is first requested. ```typescript import { Query } from "mobx-tanstack-query"; // enableOnDemand: defer fetch until .data is first accessed const lazyOnDemandQuery = new Query({ queryClient, enableOnDemand: true, queryKey: ["heavy-data"], queryFn: async () => fetch("/api/heavy").then(r => r.json()), }); // Nothing happens here lazyOnDemandQuery.data; // fetch starts NOW ``` -------------------------------- ### createInfiniteQuery Function Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/preset/createInfiniteQuery.md The `createInfiniteQuery` function is a factory that abstracts the creation of infinite queries. It accepts a query function and an optional options object, simplifying the setup process. ```APIDOC ## createInfiniteQuery ### Description This is an alternative to `new InfiniteQuery()` for creating infinite query instances. ### API Signature ```ts createInfiniteQuery(queryFn, otherOptionsWithoutFn?) ``` ### Parameters - **queryFn** (function) - The function that fetches your data. It receives an object with `signal`, `queryKey`, and `pageParam`. - **otherOptionsWithoutFn** (object, optional) - Additional options for the infinite query, such as `initialPageParam`, `queryKey`, and `getNextPageParam`. ### Usage Example ```ts import { createInfiniteQuery } from "mobx-tanstack-query/preset"; const query = createInfiniteQuery(async ({ signal, pageParam }) => { const response = await petsApi.fetchPetsApi({ signal, pageParam }); return response.data; }, { initialPageParam: 1, queryKey: ['pets'], getNextPageParam: (lastPage, _, lastPageParam) => { return lastPage.length ? lastPageParam + 1 : null; }, }); ``` ``` -------------------------------- ### QueryClient Persistence with Persister Plugins Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Integrate TanStack Query's persister plugins to persist cache across page reloads. This example uses createAsyncStoragePersister with localStorage and lz-string for serialization/deserialization. ```typescript import { QueryClient } from "mobx-tanstack-query"; import { createAsyncStoragePersister } from "@tanstack/query-async-storage-persister"; import { persistQueryClient } from "@tanstack/react-query-persist-client"; import { compress, decompress } from "lz-string"; export const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: Infinity }, }, }); persistQueryClient({ queryClient: queryClient as any, persister: createAsyncStoragePersister({ storage: window.localStorage, serialize: (data) => compress(JSON.stringify(data)), deserialize: (data) => JSON.parse(decompress(data)), }), maxAge: Infinity, }); ``` -------------------------------- ### Creating a Query Instance Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Shows how to instantiate a Query with essential parameters like queryKey and queryFn, and optional parameters like abortSignal. ```APIDOC ### Another examples Create an instance of `Query` with [`queryKey`](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) and [`queryFn`](https://tanstack.com/query/latest/docs/framework/react/guides/query-functions) parameters ```ts import { Query } from "@mobx-tanstack/query"; // Assume queryClient, abortSignal, and petsApi are defined elsewhere // const queryClient = new QueryClient(); // const abortSignal = new AbortController(); // const petsApi = { fetchPets: async ({ signal }: { signal: AbortSignal }) => ({ json: async () => [{ id: 1, name: "Fluffy" }] }) }; const petsQuery = new Query({ queryClient, abortSignal, // Helps you to automatically clean up query or use `lazy` option queryKey: ['pets'], queryFn: async ({ signal, queryKey }) => { const response = await petsApi.fetchPets({ signal }); return await response.json(); }, }); // ... console.log( petsQuery.data, petsQuery.isLoading ) ``` ::: info This query is enabled by default! This means that the query will immediately call the `queryFn` function, i.e., make a request to `fetchPets` This is the default behavior of queries according to the [**query documtation**](https://tanstack.com/query/latest/docs/framework/react/guides/queries) ::: ``` -------------------------------- ### Query Initialization with QueryClient Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Demonstrates how to initialize a Query with a QueryClient and configure default options for queries and mutations. ```APIDOC ## QueryClient Configuration ### Description This section shows how to configure a `QueryClient` with default options for queries and mutations, including options for error handling, key hashing, refetching behavior, and retries. It also highlights the importance of calling `mount()` on the `QueryClient` for certain features to work. ### Example ```ts import { hashKey, QueryClient } from "@tanstack/query-core"; export const queryClient = new QueryClient({ defaultOptions: { queries: { throwOnError: true, queryKeyHashFn: hashKey, refetchOnWindowFocus: "always", refetchOnReconnect: "always", staleTime: 5 * 60 * 1000, retry: (failureCount, error) => { if ("status" in error && Number(error.status) >= 500) { return failureCount < 3; } return false; }, }, mutations: { throwOnError: true, }, }, }); // enable all subscriptions for online/offline and window focus/blur queryClient.mount(); ``` **Note**: If you work with `QueryClient` directly, calling `mount()` is not needed. ``` -------------------------------- ### QueryClient Constructor and Configuration Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/QueryClient.md Demonstrates how to instantiate the QueryClient with custom configurations for default query and mutation options, as well as lifecycle hooks. ```APIDOC ## QueryClient Constructor ### Description Instantiates a new QueryClient with optional configuration. ### Constructor Signature ```ts new QueryClient(config?: QueryClientConfig) ``` ### Configuration Interface (`QueryClientConfig`) ```ts interface QueryClientConfig { defaultOptions?: DefaultOptions & { queries: QueryFeatures; mutations: MobxMutatonFeatures; }; hooks?: QueryClientHooks; } ``` ### `defaultOptions.queries` Features Configurations exclusively for `Query` and `InfiniteQuery`. **Example:** ```ts { queries: { lazy: true, enableOnDemand: true, throwOnError: true, refetchOnWindowFocus: false, refetchOnReconnect: false, staleTime: 0, retry: false, } } ``` ### `defaultOptions.mutations` Features Configurations exclusively for `Mutation`. **Example:** ```ts { mutations: { invalidateByKey: true, resetOnDestroy: true, lazy: true, } } ``` ### `hooks` Entity lifecycle events. **Available Hooks:** - `onQueryInit`: Triggered when a `Query` is created. - `onInfiniteQueryInit`: Triggered when an `InfiniteQuery` is created. - `onMutationInit`: Triggered when a `Mutation` is created. - `onQueryDestroy`: Triggered when a `Query` is destroyed. - `onInfiniteQueryDestroy`: Triggered when an `InfiniteQuery` is destroyed. - `onMutationDestroy`: Triggered when a `Mutation` is destroyed. ### Usage Example ```ts import { QueryClient } from "mobx-tanstack-query"; const client = new QueryClient({ hooks: { onQueryInit: (query) => { console.log("[Init] Query:", query.queryKey); }, onMutationDestroy: (mutation) => { console.log("[Destroy] Mutation:", mutation.options.mutationKey); }, }, defaultOptions: { queries: { enableOnDemand: true, }, mutations: { invalidateByKey: true, }, }, }); ``` ``` -------------------------------- ### Create and Use Mutation Instance Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Mutation.md Demonstrates how to create a Mutation instance with essential parameters like queryClient, mutationFn, and callbacks for lifecycle events. It also shows how to execute the mutation and access its results. ```typescript import { Mutation } from "mobx-tanstack-query"; import { petsApi } from "@/shared/apis" import { queryClient } from "@/shared/config" const petCreateMutation = new Mutation({ queryClient, mutationFn: async (petName: string) => { const response = await petsApi.createPet(petName); return await response.json(); }, onMutate: () => { console.log('Start creating pet'); }, onSuccess: (newPet) => { // Invalidate cache after succeed mutation queryClient.invalidateQueries({ queryKey: ['pets'] }); console.log('Pet has been created:', newPet); }, onError: (error) => { console.error('Failed to create pet:', error.message); }, }); ... const result = await petCreateMutation.mutate('Fluffy'); console.info(result.data, result.isPending, result.isError); ``` -------------------------------- ### Query ErrorUpdateCount Property Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Get the total count of all errors encountered by the query using 'errorUpdateCount'. ```APIDOC ### `errorUpdateCount: number` The sum of all errors. ``` -------------------------------- ### QueryClient Initialization with Custom Hooks and Options Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/QueryClient.md Demonstrates creating a QueryClient instance with custom lifecycle hooks for queries and mutations, alongside default query and mutation options. ```typescript import { QueryClient } from "mobx-tanstack-query"; // Create a client with custom hooks const client = new QueryClient({ hooks: { onQueryInit: (query) => { console.log("[Init] Query:", query.queryKey); }, onMutationDestroy: (mutation) => { console.log("[Destroy] Mutation:", mutation.options.mutationKey); }, }, defaultOptions: { queries: { enableOnDemand: true, }, mutations: { invalidateByKey: true, }, }, }); // Use standard QueryClient methods const data = client.getQueryData(["todos"]); ``` -------------------------------- ### Query ErrorUpdatedAt Property Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Get the timestamp for when the query most recently returned the status as 'error' using 'errorUpdatedAt'. ```APIDOC ### `errorUpdatedAt: number` The timestamp for when the query most recently returned the `status` as "error". ``` -------------------------------- ### Query DataUpdatedAt Property Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Get the timestamp for when the query most recently returned the status as 'success' using 'dataUpdatedAt'. ```APIDOC ### `dataUpdatedAt: number` The timestamp for when the query most recently returned the `status` as "success". ``` -------------------------------- ### Configure Query Client with Default Options Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Set up a QueryClient with default options for queries and mutations, including error handling, key hashing, refetching behavior, and retry logic. Manually mount the client to enable subscriptions for window focus and reconnect events. ```typescript import { hashKey, QueryClient } from "@tanstack/query-core"; export const queryClient = new QueryClient({ defaultOptions: { queries: { throwOnError: true, queryKeyHashFn: hashKey, refetchOnWindowFocus: "always", refetchOnReconnect: "always", staleTime: 5 * 60 * 1000, retry: (failureCount, error) => { if ("status" in error && Number(error.status) >= 500) { return failureCount < 3; } return false; }, }, mutations: { throwOnError: true, }, }, }); // enable all subscriptions for online\offline and window focus/blur queryClient.mount(); ``` -------------------------------- ### Query FailureCount Property Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Get the number of times the query has failed using 'failureCount'. This count resets on success. ```APIDOC ### `failureCount: number` The failure count for the query. - Incremented every time the query fails. - Reset to `0` when the query succeeds. ``` -------------------------------- ### Lifecycle Hooks (onInit, onDone, onError) Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md These are optional constructor arguments that allow you to hook into the query's lifecycle. `onInit` runs when the query is ready, `onDone` is an alias for registering an `onDone` listener immediately, and `onError` is an alias for registering an `onError` listener immediately. ```APIDOC ### `onInit` (constructor) Optional. Runs once when the query is ready; receives the instance. If you use [`QueryClient`](/api/QueryClient) hooks, `onQueryInit` runs after `onInit`. ### `onDone` (constructor) Optional. Same as registering [`onDone(...)`](#ondone-listener) on the instance right away; you can still add more listeners later. ### `onError` (constructor) Optional. Same as registering [`onError(...)`](#onerror-listener) on the instance right away; you can still add more listeners later. ``` -------------------------------- ### Accessing Query Options Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Illustrates how to access the configuration options of a query instance. This allows inspection of settings like `enabled`. ```typescript const query = new Query({ enabled: false }); console.log(query.options.enabled); // false ``` -------------------------------- ### Create and Observe a Query Source: https://github.com/js2me/mobx-tanstack-query/blob/master/README.md Instantiate a new Query with a query client, key, and fetch function. Observe query loading state using MobX reactions. ```typescript import { Query } from "mobx-tanstack-query"; const query = new Query({ queryClient, queryKey: ['hello', 'world'], queryFn: async () => { const response = await fetch('/hello/world'); return await response.json(); } }) reaction( () => query.isLoading, isLoading => { if (isLoading) { console.log('Loading...'); } } ) ``` -------------------------------- ### Transforming Errors in MobX Query Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Use `transformError` to normalize errors before they are exposed via the `.error` property. This example normalizes `Response` errors to a string indicating the HTTP status. ```typescript import { Query } from "mobx-tanstack-query"; // transformError: normalize errors before they appear on .error const safeQuery = new Query({ queryClient, queryKey: ["safe"], transformError: (err) => err instanceof Response ? `HTTP ${err.status}` : String(err), queryFn: async () => { throw new Response(null, { status: 401 }); }, }); safeQuery.error; // "HTTP 401" ``` -------------------------------- ### Mutation Class Usage Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Mutation.md Demonstrates how to create and use an instance of the `Mutation` class, including defining `mutationFn`, `onMutate`, `onSuccess`, and `onError` callbacks, and how to trigger mutations and access results. ```APIDOC ## Usage Create an instance of `Mutation` with [`mutationFn`](https://tanstack.com/query/latest/docs/framework/react/guides/mutations) parameter ```ts import { Mutation } from "mobx-tanstack-query"; import { petsApi } from "@/shared/apis" import { queryClient } from "@/shared/config" const petCreateMutation = new Mutation({ queryClient, mutationFn: async (petName: string) => { const response = await petsApi.createPet(petName); return await response.json(); }, onMutate: () => { console.log('Start creating pet'); }, onSuccess: (newPet) => { // Invalidate cache after succeed mutation queryClient.invalidateQueries({ queryKey: ['pets'] }); console.log('Pet has been created:', newPet); }, onError: (error) => { console.error('Failed to create pet:', error.message); }, }); ... const result = await petCreateMutation.mutate('Fluffy'); console.info(result.data, result.isPending, result.isError); ``` ``` -------------------------------- ### Instance Methods for Cache and Lifecycle Management Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Details key instance methods available on `Query` objects for managing cache, triggering refetches, updating data, and controlling the query lifecycle. ```APIDOC ## Query — Instance methods Key methods available on every `Query` instance for cache and lifecycle management. ```ts import { Query } from "mobx-tanstack-query"; const petsQuery = new Query({ queryClient, queryKey: ["pets"], queryFn: async ({ signal }) => fetch("/api/pets", { signal }).then(r => r.json()), }); // Trigger a background refetch and wait for result const { data } = await petsQuery.refetch(); // Optimistically update cache without a network request petsQuery.setData((prev) => [...(prev ?? []), { id: 99, name: "New Pet" }]); // Mark cached data as stale and trigger refetch for all observers await petsQuery.invalidate(); // Cancel the in-flight network request await petsQuery.cancel(); // Reset to initial pending state (removes cached data) await petsQuery.reset(); // Remove entry entirely from QueryClient cache await petsQuery.remove(); // Dynamically update query options at runtime petsQuery.update({ staleTime: 60_000, enabled: false }); // Subscribe to success / error events imperatively const unsubDone = petsQuery.onDone((data) => console.log("Data:", data)); const unsubError = petsQuery.onError((err) => console.error("Error:", err)); // Destroy query to free MobX reactions and QueryObserver subscription petsQuery.destroy(); ``` ``` -------------------------------- ### Query Instance Methods for Cache and Lifecycle Management Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Provides an overview of key instance methods for managing query cache and lifecycle, including refetching, data manipulation, invalidation, cancellation, resetting, removal, updates, and event subscriptions. Ensure `queryClient` is initialized. ```typescript import { Query } from "mobx-tanstack-query"; const petsQuery = new Query({ queryClient, queryKey: ["pets"], queryFn: async ({ signal }) => fetch("/api/pets", { signal }).then(r => r.json()), }); // Trigger a background refetch and wait for result const { data } = await petsQuery.refetch(); // Optimistically update cache without a network request petsQuery.setData((prev) => [...(prev ?? []), { id: 99, name: "New Pet" }]); // Mark cached data as stale and trigger refetch for all observers await petsQuery.invalidate(); // Cancel the in-flight network request await petsQuery.cancel(); // Reset to initial pending state (removes cached data) await petsQuery.reset(); // Remove entry entirely from QueryClient cache await petsQuery.remove(); // Dynamically update query options at runtime petsQuery.update({ staleTime: 60_000, enabled: false }); // Subscribe to success / error events imperatively const unsubDone = petsQuery.onDone((data) => console.log("Data:", data)); const unsubError = petsQuery.onError((err) => console.error("Error:", err)); // Destroy query to free MobX reactions and QueryObserver subscription petsQuery.destroy(); ``` -------------------------------- ### Basic createQuery Usage Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/preset/createQuery.md Use this to create a query with a query function and options. The query client will be automatically mounted. ```typescript import { createQuery } from "mobx-tanstack-query/preset"; const query = createQuery(async ({ signal, queryKey }) => { const response = await petsApi.fetchPets({ signal }); return response.data; }, { queryKey: ['pets'], }) ``` -------------------------------- ### Create and Configure QueryClient with Persistence Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/QueryClient.md Instantiate a QueryClient and attach the persistence feature using a custom persister with compression and decompression. Ensure the QueryClient is cast to 'any' if type issues arise. ```typescript import { QueryClient } from "mobx-tanstack-query"; import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister'; import { persistQueryClient } from '@tanstack/react-query-persist-client'; import { compress, decompress } from 'lz-string' export const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: Infinity } }, }) persistQueryClient({ queryClient: queryClient as any, persister: createAsyncStoragePersister({ storage: window.localStorage, serialize: (data) => compress(JSON.stringify(data)), deserialize: (data) => JSON.parse(decompress(data)), }), maxAge: Infinity, }); ``` -------------------------------- ### Create a QueryClient Instance Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/introduction/getting-started.md Instantiate a QueryClient with custom default options for queries and mutations. Includes retry logic for server errors and specific query settings like staleTime. ```typescript import { QueryClient } from "mobx-tanstack-query"; import { hashKey } from "@tanstack/query-core"; export const queryClient = new QueryClient({ defaultOptions: { queries: { throwOnError: true, queryKeyHashFn: hashKey, refetchOnWindowFocus: true, refetchOnReconnect: true, staleTime: 10 * 60 * 1000, retry: (failureCount, error) => { if (error instanceof Response && error.status >= 500) { return failureCount < 3; } return false; }, }, mutations: { throwOnError: true, }, }, }); ``` -------------------------------- ### CreateQuery for Simple Data Fetching Source: https://context7.com/js2me/mobx-tanstack-query/llms.txt Use createQuery from the preset API for straightforward data fetching with a pre-configured QueryClient. You can pass the queryFn first, followed by options, or vice-versa. Dynamic options can be used with observable state for automatic re-fetching. ```typescript import { createQuery } from "mobx-tanstack-query/preset"; // Shorthand: pass queryFn first, then options const petsQuery = createQuery( async ({ signal, queryKey }) => { const response = await fetch(`/api/pets`, { signal }); return response.json() as Promise; }, { queryKey: ["pets"], staleTime: 60_000, }, ); console.log(petsQuery.isLoading); // true console.log(petsQuery.data); // undefined → Pet[] once resolved // Dynamic options with observable state import { observable } from "mobx"; const filter = observable.box("active"); const filteredPetsQuery = createQuery( async ({ queryKey, signal }) => { const res = await fetch(`/api/pets?status=${queryKey[1]}`, { signal }); return res.json(); }, { queryKey: () => ["pets", filter.get()] as const, enabled: ({ queryKey }) => !!queryKey[1], }, ); filter.set("inactive"); // query automatically re-runs with new key ``` -------------------------------- ### Query Instance with QueryKey and QueryFn Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Create a Query instance with essential parameters like 'queryKey' and 'queryFn'. The 'abortSignal' can be used for automatic cleanup or with the 'lazy' option. ```typescript const petsQuery = new Query({ queryClient, abortSignal, // Helps you to automatically clean up query or use `lazy` option queryKey: ['pets'], queryFn: async ({ signal, queryKey }) => { const response = await petsApi.fetchPets({ signal }); return await response.json(); }, }); ... console.log( petsQuery.data, petsQuery.isLoading ) ``` -------------------------------- ### Using queryKey for Data Passing Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/Query.md Illustrates how the `queryKey` can be used not only as a cache key but also to pass necessary data to the `queryFn`. ```APIDOC ## `queryKey` for Data Passing ### Description `queryKey` serves as both a cache identifier and a mechanism to supply data required by the `queryFn`. This example shows how to extract data from the `queryKey` within the `queryFn`. ### Example ```ts const petQuery = new Query(queryClient, () => ({ queryKey: ["pets", "Fluffy"] as const, queryFn: async ({ queryKey }) => { const petName = queryKey[1]!; const response = await petsApi.getPetByName(petName); return await response.json(); }, })); ``` ``` -------------------------------- ### Creating an Infinite Query with createInfiniteQuery Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/preset/createInfiniteQuery.md Use createInfiniteQuery to set up an infinite query. It requires a query function and optional configuration options. The query function receives context like signal, queryKey, and pageParam, and should return data or a promise resolving to data. Configure initialPageParam, queryKey, and getNextPageParam for pagination. ```typescript import { createInfiniteQuery } from "mobx-tanstack-query/preset"; const query = createInfiniteQuery(async ({ signal, queryKey, pageParam, }) => { const response = await petsApi.fetchPetsApi({ signal, pageParam }) return response.data; }, { initialPageParam: 1, queryKey: ['pets'], getNextPageParam: (lastPage, _, lastPageParam) => { return lastPage.length ? lastPageParam + 1 : null; }, }); ``` -------------------------------- ### QueryClient Configuration Interface Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/QueryClient.md Outlines the structure for configuring the QueryClient, including default options for queries and mutations, and custom hooks. ```typescript import { DefaultOptions } from "@tanstack.query-core"; interface QueryClientConfig { defaultOptions?: DefaultOptions & { queries: QueryFeatures; mutations: MobxMutatonFeatures; }; hooks?: QueryClientHooks; } ``` -------------------------------- ### Using the `using` Keyword with Queries Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/api/other.md Leverage the `using` keyword for automatic resource management of queries. This requires the `@babel/plugin-proposal-explicit-resource-management` Babel plugin. The query will be destroyed after its scope ends. ```typescript import { createQuery } from "mobx-tanstack-query/preset"; class DataModel { async getData() { using query = createQuery(() => yourApi.getData(), { queryKey: ["data"] }); await when(() => !query.isLoading); return query.data!; } } const dataModel = new DataModel(); const data = await dataModel.getData(); // after call getData() created Query // will be destroyed ``` -------------------------------- ### Using Queries with MobX Classes Source: https://github.com/js2me/mobx-tanstack-query/blob/master/docs/introduction/getting-started.md Integrate queries within a MobX class using observable properties and actions. Includes abort controller for cleanup and dynamic query options. ```typescript import { observable, action } from "mobx"; import { Query } from "mobx-tanstack-query"; class MyViewModel { abortController = new AbortController(); @observable accessor fruitName = "apple"; fruitQuery = new Query({ queryClient, abortSignal: this.abortController.signal, // Don't forget about that! queryFn: async ({ queryKey }) => { const response = await fetch(`/api/fruits/${queryKey[1]}`); return await response.json(); }, options: () => ({ enabled: !!this.fruitName, queryKey: ["fruits", this.fruitName], }), }); @action setFruitName(fruitName: string) { this.fruitName = fruitName; } destroy() { this.abortController.abort(); } } ```