2
头图

Cache Status and Debugging Tools

write in front

Since there are few more systematic react-query tutorials in China, the author hopes to write a more comprehensive tutorial based on the official documents and the content of the official courses. This article will use various examples as entry points to explain relevant knowledge points as easily as possible. If there are any mistakes, please point them out in the comment area, and the author will correct them as soon as possible.

Table of contents

Because the cache state is behind the scenes, it is difficult to visually display the relevant changes. Therefore, this chapter will also introduce the relevant use of debugging tools to explain in detail and visually display the changes of the relevant state.

cache state

react-query usually obtains data when the component is mounted; after obtaining the data, it stores the data in the cache and provides the data to the component for use.

In the process of acquiring data by react-query, it mainly goes through the following three states:

  • loading
  • error
  • success

The process relationship of these three states ( status ) is as follows:

 graph TD
loading --> success
loading --> error

For students with development experience, it should not be difficult to understand that after requesting the interface, either success or failure.

The above three states actually correspond to useQuery in the hook isLoading , isSuccess , isError . You can also obtain loading , success , error through the status attribute.

When react-query performs a backend request query, it will have the following three states:

  • idle : Idle, indicating that there is no need to obtain data from the backend
  • fetching : Get data, indicating that data is currently being obtained from the backend
  • paused : Pause, which means that the original attempt to get data from the backend, but it is usually paused due to lack of networking

fetchStatus will cycle through three states: idle , fetching , paused

 graph TD
idle --> fetching
fetching --> paused
paused --> fetching
fetching --> idle

📢 Attention

In react-query status is loading status (or isLoading is true the first time to get 77caba38--- from the backend successfully) The previous state, you can view this online example to understand the cycle in which this state lasts: View the online example

And fetchStatus is fetching status (or isFetching is true ) means each time the data is loaded from the backend the first time to get the data).

The entire life cycle, for example:

If you use react-query to request the issue list of react from the Github interface, the result of your request will be marked in status as success or error , or from isSuccess , isError to judge whether the request succeeded or failed.

After requesting the backend data successfully, when writing to the cache, the cache status at this time is fresh(最新) , but soon (the default expiration time is 0ms ) will become stale(老旧) Status.

If every component of the issue list using react is uninstalled, the cached status of the issue list data will be marked as inactive(不活跃) status. At this time, the data will not be deleted until after a period of time (5 minutes by default), react-query will delete the data from the cache.

Before changing to the state of inactive(不活跃) , the data will switch back and forth between fresh(最新) and stale(老旧) , and the interface request state will also be in idle to switch between fetching .

👇🏻The details of the example process will be described in detail below

Use DevTools to observe cache state changes

In order to observe the changes of the cache state more intuitively, you can use DevTools to display it visually. You need to add the following code in your entry file

 import * as React from 'react';
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { QueryClient, QueryClientProvider } from 'react-query';
+ import { ReactQueryDevtools } from 'react-query/devtools';

import App from './App';

const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
const queryClient = new QueryClient();

root.render(
  <StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
+      <ReactQueryDevtools initialIsOpen />
    </QueryClientProvider>
  </StrictMode>
);

In the above sample code, we introduced and set the ReactQueryDevtools component initialIsOpen attribute, so the debugging tool will be opened by default

Then we start to request the interface, you can see an overview of all the current cache status in the debugging tool, as shown in the following figure:

You can also open the online demo observation and click the [Refresh] button in the example to observe the change of the cache status.

状态概览

fresh(最新) Data and stale(老旧) Data

Whether react-query will trigger the query function and get data from the backend interface is related to the cache status: fresh(最新) status or stale(老旧) status. If the cache status is stale(老旧) , it means that the query will be eligible for re-fetching, but if the cache status is fresh(最新) , it will not be re-fetched.

Attention 📢

It's important to keep these things in mind if you want more control over the frequency of interface requests.

By default, the cache status of the data returned by the backend will immediately ( {staleTime: 0} ) change from fresh(最新) to stale(老旧) .

In fact, this is not difficult to understand, because when you request the data, the backend data may change, so when you get the data returned by the backend, the cache status is stale(陈旧) .

You can set staleTime in the configuration to a number of milliseconds, then the cache will expire in staleTime milliseconds (from fresh(最新) to stale(陈旧) )

Note: At this time staleTime cannot be 0, otherwise it has no meaning.

In the following example, set staleTime to 60s, you can observe the cache status in DevTools:

Click to view online demo

 import * as React from 'react';
import { useQuery } from 'react-query';
import './style.css';

export default function App() {
  const getRepos = (username) =>
    fetch(`https://api.github.com/users/${username}/repos`).then((res) =>
      res.json()
    );

  const reposQuery = useQuery(
    ['repos', 'facebook'],
    () => getRepos('facebook'),
+    { staleTime: 1000 * 60 }
  );
  return (
    <div>
      <button
        onClick={() => {
          reposQuery.refetch();
        }}
      >
        刷新
      </button>
      <p>
        {reposQuery.isLoading && '首次加载中...'}
        {reposQuery.isFetching && '刷新中...'}
      </p>
      <p>{JSON.stringify(reposQuery.data)}</p>
    </div>
  );
}

If staleTime is set to Infinity , it means that the data currently queried will only be fetched once and will be cached throughout the life cycle of the web page.

It should now be clear how the cache state changed from fresh(最新) to stale(老旧) . So once the data becomes stale(老旧) will it be re-acquired? No, but it needs to meet certain trigger conditions. These trigger conditions are described below:

When will the refetch data operation be triggered?

In react-query, the cache is not re-fetched when it is converted from fresh(最新) to stale(老旧) state. Instead, it relies on the following five trigger conditions to re-fetch data data:

①When the component is mounted

When the component is first loaded, it will trigger the data fetching. If the component is unloaded and then loaded again, the data re-fetching will also be triggered at this time.

②When the query key is changed

As mentioned in the example in the previous chapter, when the query key is changed, the data retrieval will be triggered automatically.

ps: If there are objects in your query keys, don't worry that react-query can't detect changes, because react-query will perform deep comparisons.

③ The page is refocused

When the user refocuses the browser (for example, opens the page to be debugged in the browser, then switches to vscode to edit the code, after editing, he needs to see the effect of the debugged page, and then switches to the browser), or switch tabs (For example, when two browser tabs are opened, one is Baidu, the other is your page, and you switch from Baidu's tab to your page), react-query will automatically re-fetch data.

This trigger condition is enabled by default. If you want to disable this trigger condition, you can set the refetchOnWindowFocus option to false to disable it.

④Network reconnection

After the current user disconnects from the Internet and reconnects to the Internet, react-query will retrieve the data again. For example, if your user is holding a mobile phone in an underground passage, the signal is interrupted and the network is disconnected. When the user comes out of the underground passage, after the signal is connected, the network is reconnected, and the data will be re-acquired at this time.

This trigger condition is also enabled by default. If you want to turn off this trigger condition, you can set the refetchOnReconnect option to false to disable it.

⑤ Regular refresh

This is a trigger condition that needs to be configured by yourself. When you set refetchInterval in the configuration as a number (representing xxx milliseconds). Regardless of whether the data is in the cached state of fresh(最新) or stale(老旧) , react-query will re-fetch the data within the millisecond interval you set

The above five are the built-in re-acquisition trigger conditions of react-query.

Attention ❗️❗️❗️❗️📢

Except for regular refresh, other triggers need the state to be stale(陈旧) to trigger, you can try to defocus the page in the previous example , and then focus (that is, the trigger condition of ③) , you will find that when the data is in the fresh(最新) state, the data is not re-requested.

clear cache

When the cache state is in inactive(不活跃) state or the component that uses this query data is uninstalled, after more than 5 minutes (by default), react-query will automatically clear the cache.

If you want to customize this time, you can use the cacheTime configuration. In the following example, set cacheTime to 0. The effect is that when the query data is in inactive , immediately remove from cache.

 const userQuery = useQuery(
  ["user", username],
  () =>
    fetch(`https://api.github.com/users/${username}`)
    .then(res => res.json()),
  { cacheTime: 0 }
);

When the query data is deleted from the cache, the performance at this time is the same as the query data has never been loaded. Before the query data is returned from the backend, the loading status will be seen. After the data is obtained, the query data will be seen.


修仙大橙子
108 声望17 粉丝

前端工程师