React-Query是什么
简单的来说这是一个适用于React Hooks 的请求库,这个库将帮助你获取、同步、更新和缓存你的远程数据, 提供两个简单的hooks,就能完成增删改查等操作,React-Query使用声明式管理服务端状态,可以使用零配置开箱即用地处理缓存,后台更新和陈旧数据。
说着可能没什么概念,直接看例子
Example 1
import { QueryClient, QueryClientProvider, useQuery } from 'react-query'
const queryClient = new QueryClient()
export const App = () => {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}
const Example = () => {
const { isLoading, error, data } = useQuery('repoData', () =>
fetch(
'https://api.github.com/repos/tannerlinsley/react-query',
).then((res) => res.json()),
)
if (isLoading) return 'Loading...'
if (error) return 'An error has occurred: ' + error.message
return (
<div>
<h1>{data.name}</h1>
<p>{data.description}</p>
<strong>👀 {data.subscribers_count}</strong>{' '}
<strong>✨ {data.stargazers_count}</strong>{' '}
<strong>🍴 {data.forks_count}</strong>
</div>
)
}
React-Query中的Query指一个异步请求的数据源。
例子中repoData字符串就是这个query独一无二的key。
可以看到,React-Query封装了完整的请求中间状态(isLoading、isError...)。
不仅如此,React-Query还为我们做了如下工作:
-
多个组件请求同一个
query时只发出一个请求 -
缓存数据失效/更新策略(判断缓存合适失效,失效后自动请求数据)
-
对失效数据垃圾清理
数据的CRUD由2个hook处理:
-
useQuery处理数据的查 -
useMutation处理数据的增/删/改
Example 2
github 链接
demo主要的例子放在src/App.tsx
服务端的响应主要放在server.js中
运行yarn start 会开启一个前端服务器和一个后端服务器(用于模拟请求)
import { ReactQueryDevtools} from 'react-query/devtools'
import {
useQuery,
useMutation,
useQueryClient,
QueryClient,
QueryClientProvider,
} from 'react-query'
type User = {
id: number;
name: string;
}
const queryClient = new QueryClient()
function App() {
return (
<QueryClientProvider client={queryClient}>
<UserPage />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
)
}
const getAllUsers = async ():Promise<{responseId:number,result:User[]}> => {
const res = await fetch('http://localhost:8080/getUserList')
return res.json()
}
const findUser = async ({queryKey}:{queryKey: (string | number)[]}):Promise<{responseId:number,result:User[]}> =>{
const [,id] = queryKey
const res = await fetch(`http://localhost:8080/getUserById?userId=${id}`)
return res.json()
}
function UserPage() {
const queryClient = useQueryClient()
//userList,是唯一的key,用于缓存结果,避免重复请求,当mutation向后端提交数据后,queryClient.invalidateQueries('userList')会触发自动更新
const {data,isError,isLoading,} = useQuery('userList', getAllUsers)
//不重要:只是为了实现user Id自增,这里只是为了方便演示
const users = data?.result || []
const lastUserId = users[users.length-1]?.id ?? 0
//查询第五个用户: 唯一key,也可以是数组,用于传递一些依赖,有时候我们通过id 或pageNumber查询,这样可以更好的缓存结果
const {data:currentUser} = useQuery(['userList',5], findUser)
// update
const mutation = useMutation((newUser:User)=>fetch('http://localhost:8080/updateUserList',{
method:'POST',
body:JSON.stringify(newUser)
}).then(res=>res.json()), {
onSuccess: () => queryClient.invalidateQueries('userList'),
})
if(isLoading){
return <div>loading....</div>
}
return (
<div>
<h1>当前用户</h1>
<ul>
{
currentUser?.result.map(item=> (
<li key={item.id}>{item.name}</li>
))
}
</ul>
<h1>用户列表</h1>
<ul>
{data?.result.map(todo => (
<li key={todo.id}>{todo.name}</li>
))}
</ul>
<button
onClick={() => {
mutation.mutate({
id: lastUserId+1,
name: `Do Laundry ${lastUserId+1}`,
})
}}
>
添加新用户
</button>
</div>
)
}
使用 useQueries 的动态并行查询
function App({ users }) {
const userQueries = useQueries(
users.map(user => {
return {
queryKey: ['user', user.id],
queryFn: () => fetchUserById(user.id),
}
})
)
}
依赖查询 (enabled 选项)
// Get the user
const { data: user } = useQuery(['user', email], getUserByEmail)
const userId = user?.id
// Then get the user's projects
const { isIdle, data: projects } = useQuery(
['projects', userId],
getProjectsByUser,
{
// The query will not execute until the userId exists
enabled: !!userId,
}
)
// isIdle will be `true` until `enabled` is true and the query begins to fetch.
// It will then go to the `isLoading` stage and hopefully the `isSuccess` stage :)
Query Retries
重新发起请求
import { useQuery } from 'react-query'
// Make a specific query retry a certain number of times
const result = useQuery(['todos', 1], fetchTodoListPage, {
retry: 10, // 请求失败后会重新发起请求,最大重试次数为10
retryDelay : 1000 ,//间隔时间
keepPreviousData:true,//用于分页查询
})