目的
也就是解决了什么问题?
常规流程
请求数据 =>加载中 => 后端返回 => 如果有报错展示报错 =>刷新数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import * as React from "react";
export default function App() { const [zen, setZen] = React.useState(""); const [isLoading, setIsLoading] = React.useState(false); const [isError, setIsError] = React.useState(false); const [errorMessage, setErrorMessage] = React.useState("");
const fetchData = () => { setIsLoading(true);
fetch("https://api.github.com/zen") .then(async (response) => { if (response.status !== 200) { const { message } = await response.json();
throw new Error(message); }
return response.text(); }) .then((text: string) => { setIsLoading(false); setIsError(false); setZen(text); }) .catch((error) => { setIsLoading(false); setIsError(true); setErrorMessage(error.message); }); };
React.useEffect(() => { fetchData(); }, []);
return ( <div> <h1>Zen from Github</h1> <p> {isLoading ? "加载中..." : isError ? errorMessage : zen} </p> {" "} {!isLoading && ( <button onClick={fetchData}>{isError ? "重试" : "刷新"}</button> )} </div> ); }
|
- 使用 isLoading 来存储加载状态
- 使用 isError 来存储接口是否有错误
- 使用 errorMessage 来存储后端返回的报错信息
- 使用 zen 来存储后端返回数据存储
- 重新调用 fetchData 方法来刷新数据
修正
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import * as React from "react"; import { useQuery } from "react-query";
const fetchData = () => { return fetch("https://api.github.com/zen").then(async (response) => { if (response.status !== 200) { const { message } = await response.json();
throw new Error(message); }
return response.text(); }); };
export default function App() { const zenQuery = useQuery(["zen"], fetchData);
return ( <div> <h1>Zen from Github</h1> <p> {" "} {zenQuery.isLoading || zenQuery.isFetching ? "加载中..." : zenQuery.isError ? zenQuery.error?.message : data} </p> {" "} {!zenQuery.isLoading && !zenQuery.isFetching && ( <button onClick={() => { zenQuery.refetch(); }} > {zenQuery.isError ? "重试" : "刷新"} </button> )} </div> ); }
|
结果
为了解决这么多大量冗杂的模板代码.使用 react-query 会变得十分整洁.
上面各种 loading,error,数据刷新等等都交给 react-query 处理.
初始配置
将组件包裹在QueryClientProvider
中,和 useContext 搭配就是把 useContext 实例化的组件放在其中.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import { QueryClient, QueryClientProvider, useQuery, } from "@tanstack/react-query";
const queryClient = new QueryClient();
function Example() { const query = useQuery("todos", fetchTodos);
return ( <div> {query.isLoading ? "Loading..." : query.isError ? "Error!" : query.data ? query.data.map((todo) => <div key={todo.id}>{todo.title}</div>) : null} </div> ); }
function App() { return ( <QueryClientProvider client={queryClient}> <Example /> </QueryClientProvider> ); }
|
搭配 useContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| import { ReactNode } from "react"; import { AuthProvider } from "./auth.context"; import { QueryClient, QueryClientProvider } from "react-query";
export const AppProviders = ({ children }: { children: ReactNode }) => { return ( <QueryClientProvider client={new QueryClient()}> <AuthProvider>{children}</AuthProvider> </QueryClientProvider> ); };
import * as auth from "auth-provider"; import { FullPageLoading } from "components/lib"; import { createContext, ReactNode, useContext } from "react"; import { useQueryClient } from "react-query"; import { User } from "types/user"; import { useMount } from "utils"; import { http } from "utils/http"; import { useAsync } from "utils/use-async"; import { FullPageErrorFallback } from "../components/lib";
const AuthContext = createContext< | { user: User | null; login: (form: AuthForm) => Promise<void>; register: (form: AuthForm) => Promise<void>; logout: () => Promise<void>; } | undefined >(undefined);
AuthContext.displayName = "AuthContext";
interface AuthForm { username: string; password: string; }
const bootstrapUser = async () => { let user = null; const token = auth.getToken(); if (token) { const data = await http("me", { token }); user = data.user; } return user; };
export const AuthProvider = ({ children }: { children: ReactNode }) => {
const { run, isIdle, isLoading, isError, error, data: user, setData: setUser, } = useAsync<User | null>(); const queryClient = useQueryClient();
const login = (form: AuthForm) => auth.login(form).then(setUser); const register = (form: AuthForm) => auth.register(form).then(setUser); const logout = () => auth.logout().then(() => { setUser(null); queryClient.clear(); });
useMount(() => { run(bootstrapUser()); });
if (isIdle || isLoading) { return <FullPageLoading />; } if (isError) { return <FullPageErrorFallback error={error} />; }
return ( <AuthContext.Provider children={children} value={{ user, login, register, logout }} /> ); };
export const useAuth = () => { const context = useContext(AuthContext);
if (!context) { throw new Error("useAuth必须在AuthProvider中使用"); } return context; };
|
常用方法
查询键和查询函数
1
| const zenQuery = useQuery(["zen"], fetchData);
|
- 其中
['zen']
就是 react-query 的查询键,react-query 通过不同的查询键来标识(映射)不同接口(或是同一接口不同参数请求)返回的数据。在 react-query@4 中,查询键必须是数组。
- 而
fetchData
就是我们请求后端接口的函数,也就是查询函数.
PS:查询键内的元素可以是嵌套数组、对象、字符串、数字
例如:[‘zen’, { form: ‘confucius’ }]或[‘zen’, [‘confucius’, ‘Lao Tzu’]]
为了方便记忆,打个比方,你可以将查询键看做是你存储 localStorage 时的 key,而 value 则是通过查询函数查询到数据后,将各种我们需要的状态数据存储进入 value
使用变量作为查询键的元素时,当变量的值变化后,react-query 将会重新调用 fetchData 方法,获取新的数据,并缓存到对应变量值为 key 的缓存中。
并行请求
同时多个请求就写多个 useQuery,合并请求就用 Promise.all 包裹.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import * as React from "react"; import { useQuery } from "react-query";
const getReposAndGists = (username) => { return Promise.all([ fetch(`https://api.github.com/users/${username}/repos`).then((res) => res.json() ), fetch(`https://api.github.com/users/${username}/gists`).then((res) => res.json() ), ]); };
const ReposAndGists = ({ username }) => { const reposAndGistsQuery = useQuery(["reposAndGists", username], () => getReposAndGists(username) );
if (reposAndGistsQuery.isLoading) { return <p>加载数据中...</p>; }
if (reposAndGistsQuery.isError) { return <p>数据加载错误: {reposAndGistsQuery.error.message}</p>; }
if (!reposAndGistsQuery.data) { return null; }
const [repos, gists] = reposAndGistsQuery.data;
return ( <div> <h2>仓库列表</h2> <ul> {repos.map((repo) => ( <li key={repo.id}>{repo.name}</li> ))} </ul>
<hr />
<h2>代码片段列表</h2> <ul> {gists.map((gist) => ( <li key={gist.id}>{gist.description || "暂无描述"}</li> ))} </ul> </div> ); };
export default ReposAndGists;
|
动态生成请求
useQueries
.从动态获取[‘facebook’, ‘vuejs’, ‘nestjs’, ‘mongdb’],到重新批量获取了以下用户的仓库[‘microsoft’, ‘tesla’].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import * as React from "react"; import { useQueries } from "react-query";
export default function App() { const [users, setUsers] = React.useState([ "facebook", "vuejs", "nestjs", "mongodb", ]);
const getRepos = (username) => fetch(`https://api.github.com/users/${username}/repos`).then((res) => res.json() );
const userQueries = useQueries({ queries: users.map((user) => { return { queryKey: ["user", user], queryFn: () => getRepos(user), }; }), }); return ( <div> <h1>查看github用户的仓库</h1> <button onClick={() => setUsers(["microsoft", "tesla"])} > 更改获取用户 </button> {" "} {userQueries.map((query) => query.isLoading ? ( <div>加载中....</div> ) : ( <ol> {" "} {query.data.map((item) => ( <li>{item.full_name}</li> ))} </ol> ) )} </div> ); }
|
依赖请求
请求 B 接口的某个参数依赖 A 接口请求返回的内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| import * as React from "react"; import { useQuery } from "react-query";
const IssueLabelFilter = ({ owner, repo }) => { const labelsQuery = useQuery(["repos", owner, repo, "labels"], () => fetch(`https://api.github.com/repos/${owner}/${repo}/labels`).then((res) => res.json() ) );
const labels = labelsQuery.data;
const issuesQuery = useQuery( ["repos", owner, repo, "issues"], () => fetch( `https://api.github.com/repos/${owner}/${repo}/issues?labels=${labels[1].name}` ).then((res) => res.json()), {
enabled: !!labels, } );
return ( <div> <h2>标签</h2> {labelsQuery.isLoading ? ( <p>加载标签中...</p> ) : ( <ul> {labelsQuery.data.map((label) => ( <li key={label.id}>{label.name}</li> ))} </ul> )}
<hr />
<h2> Issues {Array.isArray(issuesQuery.data) ? `(${labels[1].name})` : ""} </h2> {issuesQuery.isLoading ? ( <p>加载issues中...</p> ) : ( <ul> {issuesQuery.data.map((issue) => ( <li key={issue.id}>{issue.title}</li> ))} </ul> )} </div> ); };
export default function App() { return ( <div> <IssueLabelFilter owner={"facebook"} repo={"react"} /> </div> ); }
|
在 react-query 中,当该组件被加载时,组件内的 useQuery 就会开始请求。
此时明显不符合需求,需求的要求是在加载完标签列表后,获取到第二个标签,再开始请求 issues 列表。
因此就需要使用到 useQuery 的 enabled 参数,当参数值为 false 时,将会禁止请求接口。
现在回到上面的例子中,当 labelsQuery 请求还没有结果时,labels 变量值为 undefined,此时在 ① 行代码中的值为 false,当 labelsQuery 请求结束时,labels 变量值为数组,此时在 ① 行代码中的值为 true,issuesQuery 开始请求数据。完全符合需求的要求。
改进依赖查询接口一直为 loading 的问题
上面的例子中,issuesQuery 在加载后,由于处于禁用状态(配置项 enabled: false),此时 isLoading 将会一直处于 true 的状态,直到 issuesQuery 请求完成数据后变为 false。
这种提示会非常奇怪,明明有一段时间里 issuesQuery 没有真正的请求数据,为啥要一直显示加载标签中…的内容?
解决办法是:需要一个字段来区分查询函数当前并没有请求数据,处于摸鱼状态。
在 useQuery 中当 fetchStatus 字段在为 idle 时,表示当前查询函数不在运行,处于摸鱼状态^ ^
fetchStatus 一共有三个状态,fetching 状态表示当前查询函数正在运行,idle 状态表示当时查询函数不在运行。paused 状态表示查询函数尝试运行,但是无法进行请求,最可能的原因是由于当前没有联网,处于离线状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| import * as React from "react"; import { useQuery } from "react-query"; import "./style.css";
const IssueLabelFilter = ({ owner, repo }) => { const labelsQuery = useQuery(["repos", owner, repo, "labels"], () => fetch(`https://api.github.com/repos/${owner}/${repo}/labels`).then((res) => res.json() ) );
const labels = labelsQuery.data;
const issuesQuery = useQuery( ["repos", owner, repo, "issues"], () => fetch( `https://api.github.com/repos/${owner}/${repo}/issues?labels=${labels[1].name}` ).then((res) => res.json()), { enabled: !!labels, } );
return ( <div> <h2>标签</h2> {labelsQuery.isLoading ? ( <p>加载标签中...</p> ) : ( <ul> {labelsQuery.data.map((label) => ( <li key={label.id}>{label.name}</li> ))} </ul> )} <hr /> // 👇🏻下面的代码判断了在查询函数处于摸鱼状态时,不显示任何内容 ②{issuesQuery.isLoading && issuesQuery.fetchStatus === "idle" ? null : ( <div> <h2> Issues {Array.isArray(issuesQuery.data) ? `(${labels[1].name})` : ""} </h2> // 当查询函数处于干活状态时,显示加载issues中 ③{issuesQuery.isLoading ? ( <p>加载issues中...</p> ) : ( <ul> {issuesQuery.data.map((issue) => ( <li key={issue.id}>{issue.title}</li> ))} </ul> )} </div> )} </div> ); };
export default function App() { return ( <div> <IssueLabelFilter owner={"facebook"} repo={"react"} /> </div> ); }
|
useMutation
使用useMutation
进行增删除操作.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| function App() { const mutation = useMutation((newTodo) => axios.post("/todos", newTodo));
return ( <div> {mutation.isLoading ? ( "Adding todo..." ) : ( <> {mutation.isError ? ( <div>An error occurred: {mutation.error.message}</div> ) : null}
{mutation.isSuccess ? <div>Todo added!</div> : null}
<button onClick={() => { mutation.mutate({ id: new Date(), title: "Do Laundry" }); }} > Create Todo </button> </> )} </div> ); }
|
mutate 函数是一个异步函数,这意味着你不能在事件回调中直接使用它 (React16 及之前版本)。 如果你需要在 onSubmit 中访问事件,则需要将 mutate 包装在另一个函数中。 这是由于 React 事件池限制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const CreateTodo = () => { const mutation = useMutation((event) => { event.preventDefault(); return fetch("/api", new FormData(event.target)); });
return <form onSubmit={mutation.mutate}>...</form>; };
const CreateTodo = () => { const mutation = useMutation((formData) => { return fetch("/api", formData); }); const onSubmit = (event) => { event.preventDefault(); mutation.mutate(new FormData(event.target)); };
return <form onSubmit={onSubmit}>...</form>; };
|
重置修改状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const CreateTodo = () => { const [title, setTitle] = useState(""); const mutation = useMutation(createTodo);
const onCreateTodo = (e) => { e.preventDefault(); mutation.mutate({ title }); };
return ( <form onSubmit={onCreateTodo}> {mutation.error && ( <h5 onClick={() => mutation.reset()}>{mutation.error}</h5> )} <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} />
<button type="submit">Create Todo</button> </form> ); };
|
总结
通过在查询函数中,使用Promise.all
来进行接口的合并请求
通过useQueries
来进行动态的并行请求
isLoading
为true
表示第一次请求未返回结果前这段时间的状态,如果对接口进行了禁用,可以通过fetchStatus
为idle
来获取接口禁用请求这段时间的状态。
缓存状态
react-query 通常在挂载组件时获取数据;在获取数据后,将数据存储到缓存中,并将该数据提供给组件使用。
在获取数据时,有三种状态.loading
,success
,error
.
也对应useQuery
钩子中的isLoading
、isSuccess
、isError
属性
当 react-query 进行后端请求查询时,会有以下三个状态:
idle
:空闲,表示当前不需要从后端获取数据
fetching
: 获取数据,表示当前正在从后端获取数据
paused
:暂停,表示原本尝试从后端获取数据,但是通常由于未联网的原因导致暂停
fetchStatus
将会在 idle、fetching、paused 这三个状态间经历循环
在 react-query 中 status 为loading状态(或者isLoading为 true)指的是第一次从后端获取成功之前的状态.
而 fetchStatus 为fetching状态(或者isFetching为 true)指的是每次从后端获取数据的加载状态(包含第一次获取数据)。
整个生命周期:
假如你使用 react-query 从 Github 的接口请求了 react 的 issue 列表,你此次的请求结果将会在 status 中标记为 success 或 error,或者从 isSuccess、isError 中判断请求成功或者失败。
请求后端数据成功后,在写入缓存时,此时的缓存状态是fresh
(最新)状态,但是很快(默认过期时间是 0ms)就会变为stale
(老旧)状态。
如果使用 react 的 issue 列表的每个组件都被卸载后,issue 列表数据的缓存状态将会被标记为inactive
(不活跃)状态。此时数据将不会被删除,直到一段时间后(默认为 5 分钟),react-query 将会从缓存中删除该条数据。
在变为inactive
(不活跃)状态之前,该条数据将会在fresh
(最新)与stale
(老旧)之间来回切换,同时接口请求状态也会在idle
与fetching
之间切换。
fresh 最新态和 stale 老旧态
react-query 是否会触发查询函数,并从后端接口获取数据,与缓存状态是:fresh
(最新)状态或stale
(老旧)状态有关。如果缓存状态是stale
(老旧),表示该查询将会有资格重新获取,但如果缓存状态是fresh
(最新)的,就不会重新获取。
如果使用 react 的 issue 列表的每个组件都被卸载后,issue 列表数据的缓存状态将会被标记为inactive
(不活跃)状态。此时数据将不会被删除,直到一段时间后(默认为 5 分钟),react-query 将会从缓存中删除该条数据。
在变为inactive
(不活跃)状态之前,该条数据将会在fresh
(最新)与stale
(老旧)之间来回切换,同时接口请求状态也会在idle
与fetching
之间切换。
staleTime
在默认情况下,后端返回的数据其缓存状态将会立即({staleTime: 0})
从fresh
(最新)状态变为stale
(老旧)状态。
其实这样做不难理解,因为当你请求到数据后,后端的数据有可能就发生了变化,因此当拿到后端返回的数据瞬间,缓存状态就是stale
(陈旧)的了。
你可以将配置中的staleTime
,设置一个毫秒数的数字,那么缓存将会在staleTime
毫秒后过期(从fresh
(最新)变为stale
(陈旧))
如果把staleTime
设置为Infinity
,表示当前查询的数据将只会获取一次,且会在整个网页的生命周期内缓存。
触发条件
在 react-query 中并不是缓存从 fresh(最新)转换为 stale(老旧)状态时,就会重新获取。
- 当组件首次加载,将会触发数据的获取。如果组件被卸载后再次被加载,此时也会触发数据的重新获取。
- 当用户把浏览器重新聚焦,或者切换到当前选项卡。这个触发条件是默认开启的,如果希望关闭这个触发条件,可以把
refetchOnWindowFocus
选项设置为 false 来禁止。
- 网络重新连接。可以使用
refetchOnReconnect
来禁止。
- 定时刷新。当你在配置中设置
refetchInterval
为数字(代表 xxx 毫秒)时。无论此时数据是fresh
(最新)还是stale
(老旧)的缓存状态,react-query 都会在你设置的毫秒时间间隔内重新获取数据
清理缓存
在缓存状态处于inactive
(不活跃)状态或者使用这个查询数据的组件卸载时,超过 5 分钟(默认情况下)后,react-query 将会自动清除该缓存。
如果你希望自定义这个时间,你可以使用cacheTime
配置,下面的例子中将cacheTime
设置为 0,实现的效果是,当查询数据在inactive
状态时,立即从缓存中删除。
1 2 3 4 5 6
| const userQuery = useQuery( ["user", username], () => fetch(`https://api.github.com/users/${username}`).then((res) => res.json()), { cacheTime: 0 } );
|
处理错误
错误重试
当一个查询无法重新获取时,将会基于指数退避算法的时间间隔,尝试请求 3 次。 从 1s 的延迟起步,到 30s 的最大延迟。下面是默认重试策略的相关配置:
1 2 3 4 5 6
| const exampleQuery = useQuery("example", fetchExample, { retry: 3, retryDelay: (attempt) => { return Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000); }, });
|
PS: 如果只配置了 retry 的次数,那么 retry 的时间间隔,将会默认采用指数退避算法。
错误边界
使用react-error-boundary
这个包,来减少相关错误边界的配置。
需要在配置项中,配置useErrorBoundary
为true
,之后错误边界就能捕获到相关的报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| import * as React from "react"; import "./style.css"; import { ErrorBoundary } from "react-error-boundary"; import { useQuery } from "react-query";
const fetchWithError = async (url, options = {}) => { const response = await fetch(url, options);
let errorMessage = ""; if (response.status !== 200) { errorMessage += `请求错误状态码为: ${response.status}. `; }
const body = await response.json(); if (body.message) { errorMessage += body.message; }
console.log(errorMessage);
if (errorMessage) { throw new Error(errorMessage); }
return body; };
const Repos = () => { const reposQuery = useQuery( ["users"], () => fetchWithError("https://api.github.com/users/facebook/repos"), { useErrorBoundary: true, onError: (error) => console.log(error, "onError"), } );
return <div>{JSON.stringify(reposQuery.data)}</div>; };
const Gists = () => { const gistsQuery = useQuery( ["gists"], () => fetchWithError("https://api.github.com/users/facebook/gists"), { useErrorBoundary: true, onError: (error) => console.log(error, "onError"), } );
return <div>{JSON.stringify(gistsQuery.data)}</div>; };
function QueryError({ error }) { return ( <div> <h1>出现错误</h1> <p>{error.message}</p> </div> ); }
export default function App() { return ( <ErrorBoundary FallbackComponent={QueryError}> <Repos /> <Gists /> </ErrorBoundary> ); }
|
错误回调
在 react-query 中,你可以在配置中设置 onError 属性,来获取错误的回调。包含了 error 的数据。
你可以在回调中,调用消息弹窗来提示报错信息,如果你使用 ant-design 组件库,你可以这么写:
1 2 3 4 5 6 7
| const reposQuery = useQuery( ["users"], () => fetchWithError("https://api.github.com/users/facebook/repos"), { onError: (error) => message.error({ content: error.message }), } );
|
针对重新获取数据失败处理的方式
在第一次请求数据时,查询函数返回成功。在页面失焦后,重新聚焦,触发第二次请求时,查询函数返回失败。
如何处理?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import * as React from "react"; import { useQuery } from "react-query";
let count = 0;
export default function App() { const mockQuery = useQuery( ["mock"], async () => { await new Promise((resolve) => setTimeout(resolve, 1000)); if (count === 0) { count++; return "成功"; } else { throw new Error("失败"); } }, { retry: false } );
return ( <div> {" "} {mockQuery.isError ? ( <div className="error-message">{mockQuery.error.message}</div> ) : null} {mockQuery.isLoading ? "首次加载中..." : mockQuery.data} </div> ); }
|
你可以根据不同的情况来指定你的显示策略:
- 当重新获取数据失败后,你可以像上面的例子一样即显示缓存数据,又显示报错
- 也可以判断 isError 字段为 true 时,只显示报错信息,隐藏缓存数据。
更多内容
建议看官方文档