Query
With the power of createStores
function, we can easily create a hook just like useQuery
and useInfiniteQuery
in TanStack-Query (opens in a new tab) using createQuery
function.
It can dedupe multiple request, handle caching, auto-update stale data, handle retry on error, handle infinite query, and many more.
With the flexibility given in createStores
, we can extend its power according to our needs.
Query State & Network Fetching State
First of all, we need to understand the difference between these 2 types:
- Query data state
- Network fetching state
The query data state represented as status
, isLoading
, isSuccess
, isError
.
These values has no relation with network fetching state. ⚠️
For network fetching state, we use isWaiting
.
The value will be true
if the query is called and still waiting for the response.
Here is the flow of both states:
- status: "loading"
- isLoading: true
- isSuccess: false
- isError: false
- isWaiting: false
- isWaiting: true
- status: "success"
- isLoading: false
- isSuccess: true
- isError: false
- isWaiting: false
- isWaiting: true
- status: "success"
- isLoading: false
- isSuccess: true
- isError: false
- isWaiting: false
- isRefetchError: true
- isGoingToRetry: false
- isWaiting: false
- isGoingToRetry: bool(depends on option 👆)
- isWaiting: true
- status: "error"
- isLoading: false
- isSuccess: false
- isError: true
- isWaiting: false
- isGoingToRetry: false
IMPORTANT NOTE:
By default, when isWaiting
value is changed, the subscribers or the component which use the hook will not be notified.
We can change this behavior by setting up the defaultDeps
, or set it on specific component (in the dependency array).
Response Vs Data
const { isSuccess, data, response } = useMyQuery();
The response
represents the untouched response returned from the async function.
On the other hand, the data
represents the customized selection of the response obtained using the select
option.
If we didn't define the select
option, data
will be equal to response
.
Inherited from createStores
The createQuery
function inherits functionality from the createStores
function, allowing us to perform the same result and actions available in createStores
.
const useMyQuery = createQuery(
fetchMyData,
{
// 👇 Same as createStores options
defaultDeps: undefined,
onFirstSubscribe: (state) => console.log('onFirstSubscribe', state),
onSubscribe: (state) => console.log('onSubscribe', state),
onUnsubscribe: (state) => console.log('onUnsubscribe', state),
onLastUnsubscribe: (state) => console.log('onLastUnsubscribe', state),
onBeforeChangeKey: (nextKey, prevKey) => console.log('Store key changed', nextKey, prevKey),
// ... other createQuery options (explained on next chapter)
},
);
Custom reactivity (dependency array):
function QueryLoader() {
// This component doesn't care whether the query is success or error.
// It just listening to network fetching state. 👇
const { isWaiting } = useMyQuery((state) => [state.isWaiting]);
return <div>Is network fetching? {String(isWaiting)}</div>;
}
Actions outside component:
useMyQuery.get( /* ... */ );
useMyQuery.set( /* ... */ );
useMyQuery.subscribe( /* ... */ );
useMyQuery.getSubscribers( /* ... */ );
Fresh & Stale Query Concept
A query categorized as a fresh or stale depends on the comparison between the stale time config and the current time. For example, we use the default stale time, which is 3 seconds.
const useMyQuery = createQuery(fetchMyData);
const { fetch, forceFetch } = useMyQuery.get();
07:00 AM
– fetch the data07:01 AM
– get the response(Since stale time is 3 seconds, the query will be categorized as fresh until07:04 AM
)07:02 AM to 07:04 AM
🟢 fresh- By default, when a component which use the hook is mounted, the query function will not get invoked.
- By default, when a window focus event triggered, the query function will not get invoked.
- Calling
fetch()
won't affect anything. - Calling
forceFetch()
will call the query function.
07:05 AM onwards
🟠 stale- By default, when a component which use the hook is mounted, the query function will get invoked.
- By default, when a window focus event triggered, the query function will get invoked.