QueryCache
已被拆分为 QueryClient
以及更底层的 QueryCache
和 MutationCache
实例。ReactQueryConfigProvider
和 ReactQueryCacheProvider
都已被 QueryClientProvider
替换QueryCache
已经消失了。这次是真的!makeQueryCache
实用程序已被移除。QueryCache.prefetchQuery()
已被移动到 QueryClient.prefetchQuery()
ReactQueryErrorResetBoundary
和 QueryCache.resetErrorBoundaries()
已被 QueryErrorResetBoundary
和 useQueryErrorResetBoundary()
替换。QueryCache.getQuery()
已被 QueryCache.find()
替换。QueryCache.getQueries()
已被移动到 QueryCache.findAll()
。QueryCache.isFetching
已被移动到 QueryClient.isFetching()
。useQueryCache
钩子已被 useQueryClient
钩子替换。QueryFunctionContext.pageParam
传递keepPreviousData
选项mutation.mutate
不再返回 promisetrue
/false
)QueryOptions.forceFetchOnMount
选项已被 refetchOnMount: 'always'
替换QueryOptions.refetchOnMount
选项现在仅应用于其父组件,而不是所有查询观察者QueryOptions.queryFnParamsFilter
已被移除,取而代之的是新的 QueryFunctionContext
对象。QueryOptions.notifyOnStatusChange
选项已被新的 notifyOnChangeProps
和 notifyOnChangePropsExclusions
选项取代。QueryResult.clear()
函数已重命名为 QueryResult.remove()
QueryResult.updatedAt
属性已被拆分为 QueryResult.dataUpdatedAt
和 QueryResult.errorUpdatedAt
属性setConsole()
已被新的 setLogger()
函数替换QueryStatus
已从 枚举 更改为 联合类型之前版本的 React Query 非常棒,并为库带来了令人惊叹的新特性、更多魔力以及整体更好的体验。它们也带来了大规模的采用,以及大量的改进(问题/贡献),并揭示了一些需要更多润色的地方,以使库变得更好。v3 包含了这些润色。
QueryCache 包含所有查询,MutationCache 包含所有突变,而 QueryClient 可用于设置配置并与它们交互。
这有一些好处
当创建一个 new QueryClient() 时,如果你不提供 QueryCache 和 MutationCache,它们会自动为你创建。
import { QueryClient } from 'react-query'
const queryClient = new QueryClient()
import { QueryClient } from 'react-query'
const queryClient = new QueryClient()
查询和突变的默认选项现在可以在 QueryClient 中指定
请注意,现在是 defaultOptions 而不是 defaultConfig
const queryClient = new QueryClient({
defaultOptions: {
queries: {
// query options
},
mutations: {
// mutation options
},
},
})
const queryClient = new QueryClient({
defaultOptions: {
queries: {
// query options
},
mutations: {
// mutation options
},
},
})
QueryClientProvider 组件现在用于将 QueryClient 连接到你的应用程序
import { QueryClient, QueryClientProvider } from 'react-query'
const queryClient = new QueryClient()
function App() {
return <QueryClientProvider client={queryClient}>...</QueryClientProvider>
}
import { QueryClient, QueryClientProvider } from 'react-query'
const queryClient = new QueryClient()
function App() {
return <QueryClientProvider client={queryClient}>...</QueryClientProvider>
}
正如之前在弃用说明中提到的,不再有从主包创建或导出的默认 QueryCache。你必须通过 new QueryClient() 或 new QueryCache() 创建你自己的 (然后你可以将其传递给 new QueryClient({ queryCache }) )
期待已久,但它终于消失了 :)
新的 QueryClient.prefetchQuery() 函数是异步的,但不返回查询中的数据。如果你需要数据,请使用新的 QueryClient.fetchQuery() 函数
// Prefetch a query:
await queryClient.prefetchQuery('posts', fetchPosts)
// Fetch a query:
try {
const data = await queryClient.fetchQuery('posts', fetchPosts)
} catch (error) {
// Error handling
}
// Prefetch a query:
await queryClient.prefetchQuery('posts', fetchPosts)
// Fetch a query:
try {
const data = await queryClient.fetchQuery('posts', fetchPosts)
} catch (error) {
// Error handling
}
总而言之,这些提供了与以前相同的体验,但增加了控制权,可以选择要重置的组件树。有关更多信息,请参阅
QueryCache.find() 现在应该用于从缓存中查找单个查询
QueryCache.findAll() 现在应该用于从缓存中查找多个查询
请注意,现在它是一个函数而不是属性
useQueryClient
钩子替换。它为其组件树返回提供的 queryClient,除了重命名之外,不需要太多调整。
内联函数现在是向查询函数传递参数的建议方式
// Old
useQuery(['post', id], (_key, id) => fetchPost(id))
// New
useQuery(['post', id], () => fetchPost(id))
// Old
useQuery(['post', id], (_key, id) => fetchPost(id))
// New
useQuery(['post', id], () => fetchPost(id))
如果你仍然坚持不使用内联函数,你可以使用新传递的 QueryFunctionContext
useQuery(['post', id], (context) => fetchPost(context.queryKey[1]))
useQuery(['post', id], (context) => fetchPost(context.queryKey[1]))
它们以前作为查询函数中的最后一个查询键参数添加,但这对于某些模式来说被证明是困难的
// Old
useInfiniteQuery(['posts'], (_key, pageParam = 0) => fetchPosts(pageParam))
// New
useInfiniteQuery(['posts'], ({ pageParam = 0 }) => fetchPosts(pageParam))
// Old
useInfiniteQuery(['posts'], (_key, pageParam = 0) => fetchPosts(pageParam))
// New
useInfiniteQuery(['posts'], ({ pageParam = 0 }) => fetchPosts(pageParam))
新的 keepPreviousData 选项可用于 useQuery 和 useInfiniteQuery,并且会对你的数据产生相同的“延迟”效果
import { useQuery } from 'react-query'
function Page({ page }) {
const { data } = useQuery(['page', page], fetchPage, {
keepPreviousData: true,
})
}
import { useQuery } from 'react-query'
function Page({ page }) {
const { data } = useQuery(['page', page], fetchPage, {
keepPreviousData: true,
})
}
useInfiniteQuery() 接口已更改为完全支持双向无限列表。
单向
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
useInfiniteQuery(
'projects',
({ pageParam = 0 }) => fetchProjects(pageParam),
{
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
},
)
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
useInfiniteQuery(
'projects',
({ pageParam = 0 }) => fetchProjects(pageParam),
{
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
},
)
双向
const {
data,
fetchNextPage,
fetchPreviousPage,
hasNextPage,
hasPreviousPage,
isFetchingNextPage,
isFetchingPreviousPage,
} = useInfiniteQuery(
'projects',
({ pageParam = 0 }) => fetchProjects(pageParam),
{
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
getPreviousPageParam: (firstPage, pages) => firstPage.prevCursor,
},
)
const {
data,
fetchNextPage,
fetchPreviousPage,
hasNextPage,
hasPreviousPage,
isFetchingNextPage,
isFetchingPreviousPage,
} = useInfiniteQuery(
'projects',
({ pageParam = 0 }) => fetchProjects(pageParam),
{
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
getPreviousPageParam: (firstPage, pages) => firstPage.prevCursor,
},
)
单向反向
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
useInfiniteQuery(
'projects',
({ pageParam = 0 }) => fetchProjects(pageParam),
{
select: (data) => ({
pages: [...data.pages].reverse(),
pageParams: [...data.pageParams].reverse(),
}),
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
},
)
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
useInfiniteQuery(
'projects',
({ pageParam = 0 }) => fetchProjects(pageParam),
{
select: (data) => ({
pages: [...data.pages].reverse(),
pageParams: [...data.pageParams].reverse(),
}),
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
},
)
这允许更容易地操作数据和页面参数,例如,删除第一页数据及其参数
queryClient.setQueryData(['projects'], (data) => ({
pages: data.pages.slice(1),
pageParams: data.pageParams.slice(1),
}))
queryClient.setQueryData(['projects'], (data) => ({
pages: data.pages.slice(1),
pageParams: data.pageParams.slice(1),
}))
虽然旧的方式让我们回想起第一次发现 useState 时的温暖感觉,但它们并没有持续多久。现在突变返回是一个单独的对象。
// Old:
const [mutate, { status, reset }] = useMutation()
// New:
const { mutate, status, reset } = useMutation()
// Old:
const [mutate, { status, reset }] = useMutation()
// New:
const { mutate, status, reset } = useMutation()
我们收到了很多关于此行为的问题,因为用户期望 promise 的行为类似于常规 promise。
因此,mutate 函数现在被拆分为 mutate 和 mutateAsync 函数。
当使用回调时,可以使用 mutate 函数
const { mutate } = useMutation({ mutationFn: addTodo })
mutate('todo', {
onSuccess: (data) => {
console.log(data)
},
onError: (error) => {
console.error(error)
},
onSettled: () => {
console.log('settled')
},
})
const { mutate } = useMutation({ mutationFn: addTodo })
mutate('todo', {
onSuccess: (data) => {
console.log(data)
},
onError: (error) => {
console.error(error)
},
onSettled: () => {
console.log('settled')
},
})
当使用 async/await 时,可以使用 mutateAsync 函数
const { mutateAsync } = useMutation({ mutationFn: addTodo })
try {
const data = await mutateAsync('todo')
console.log(data)
} catch (error) {
console.error(error)
} finally {
console.log('settled')
}
const { mutateAsync } = useMutation({ mutationFn: addTodo })
try {
const data = await mutateAsync('todo')
console.log(data)
} catch (error) {
console.error(error)
} finally {
console.log('settled')
}
// Old:
useQuery({
queryKey: 'posts',
queryFn: fetchPosts,
config: { staleTime: Infinity },
})
// New:
useQuery({
queryKey: 'posts',
queryFn: fetchPosts,
staleTime: Infinity,
})
// Old:
useQuery({
queryKey: 'posts',
queryFn: fetchPosts,
config: { staleTime: Infinity },
})
// New:
useQuery({
queryKey: 'posts',
queryFn: fetchPosts,
staleTime: Infinity,
})
enabled 查询选项现在仅在值为 false 时禁用查询。 如果需要,可以使用 !!userId 或 Boolean(userId) 转换值,如果传递非布尔值,则会抛出一个方便的错误。
initialStale 查询选项已被删除,初始数据现在被视为常规数据。这意味着如果提供了 initialData,则查询默认会在挂载时重新获取。如果你不想立即重新获取,你可以定义一个 staleTime。
QueryOptions.forceFetchOnMount
选项已被 refetchOnMount: 'always'
替换老实说,我们积累了太多的 refetchOn____ 选项,所以这应该可以清理一下。
QueryOptions.refetchOnMount
选项现在仅应用于其父组件,而不是所有查询观察者当 refetchOnMount 设置为 false 时,任何其他组件都会被阻止在挂载时重新获取。在版本 3 中,只有设置了该选项的组件才不会在挂载时重新获取。
QueryOptions.queryFnParamsFilter
已被移除,取而代之的是新的 QueryFunctionContext 对象。queryFnParamsFilter 选项已被删除,因为查询函数现在获取 QueryFunctionContext 对象而不是查询键。
参数仍然可以在查询函数本身内进行过滤,因为 QueryFunctionContext 也包含查询键。
QueryOptions.notifyOnStatusChange
选项已被新的 notifyOnChangeProps 和 notifyOnChangePropsExclusions 选项取代。使用这些新选项,可以配置组件应在精细级别重新渲染的时间。
仅在 data 或 error 属性更改时重新渲染
import { useQuery } from 'react-query'
function User() {
const { data } = useQuery(['user'], fetchUser, {
notifyOnChangeProps: ['data', 'error'],
})
return <div>Username: {data.username}</div>
}
import { useQuery } from 'react-query'
function User() {
const { data } = useQuery(['user'], fetchUser, {
notifyOnChangeProps: ['data', 'error'],
})
return <div>Username: {data.username}</div>
}
当 isStale 属性更改时,阻止重新渲染
import { useQuery } from 'react-query'
function User() {
const { data } = useQuery(['user'], fetchUser, {
notifyOnChangePropsExclusions: ['isStale'],
})
return <div>Username: {data.username}</div>
}
import { useQuery } from 'react-query'
function User() {
const { data } = useQuery(['user'], fetchUser, {
notifyOnChangePropsExclusions: ['isStale'],
})
return <div>Username: {data.username}</div>
}
QueryResult.clear()
函数已重命名为 QueryResult.remove()虽然它被称为 clear,但它实际上只是从缓存中删除了查询。名称现在与功能匹配。
QueryResult.updatedAt
属性已被拆分为 QueryResult.dataUpdatedAt 和 QueryResult.errorUpdatedAt 属性由于数据和错误可以同时存在,因此 updatedAt 属性已被拆分为 dataUpdatedAt 和 errorUpdatedAt。
setConsole()
已被新的 setLogger() 函数替换import { setLogger } from 'react-query'
// Log with Sentry
setLogger({
error: (error) => {
Sentry.captureException(error)
},
})
// Log with Winston
setLogger(winston.createLogger())
import { setLogger } from 'react-query'
// Log with Sentry
setLogger({
error: (error) => {
Sentry.captureException(error)
},
})
// Log with Winston
setLogger(winston.createLogger())
为了防止在 React Native 中查询失败时显示错误屏幕,有必要手动更改 Console
import { setConsole } from 'react-query'
setConsole({
log: console.log,
warn: console.warn,
error: console.warn,
})
import { setConsole } from 'react-query'
setConsole({
log: console.log,
warn: console.warn,
error: console.warn,
})
在版本 3 中,当在 React Native 中使用 React Query 时,这是自动完成的。
因此,如果你之前针对 QueryStatus 枚举属性检查查询或突变的状态属性,你现在必须针对枚举先前为每个属性保留的字符串字面量进行检查。
因此,你必须将枚举属性更改为等效的字符串字面量,如下所示
这是一个你必须做的更改的示例
- import { useQuery, QueryStatus } from 'react-query'; // [!code --]
+ import { useQuery } from 'react-query'; // [!code ++]
const { data, status } = useQuery(['post', id], () => fetchPost(id))
- if (status === QueryStatus.Loading) { // [!code --]
+ if (status === 'loading') { // [!code ++]
...
}
- if (status === QueryStatus.Error) { // [!code --]
+ if (status === 'error') { // [!code ++]
...
}
- import { useQuery, QueryStatus } from 'react-query'; // [!code --]
+ import { useQuery } from 'react-query'; // [!code ++]
const { data, status } = useQuery(['post', id], () => fetchPost(id))
- if (status === QueryStatus.Loading) { // [!code --]
+ if (status === 'loading') { // [!code ++]
...
}
- if (status === QueryStatus.Error) { // [!code --]
+ if (status === 'error') { // [!code ++]
...
}
useQuery 和 useInfiniteQuery 钩子现在有一个 select 选项,用于选择或转换查询结果的部分内容。
import { useQuery } from 'react-query'
function User() {
const { data } = useQuery(['user'], fetchUser, {
select: (user) => user.username,
})
return <div>Username: {data}</div>
}
import { useQuery } from 'react-query'
function User() {
const { data } = useQuery(['user'], fetchUser, {
select: (user) => user.username,
})
return <div>Username: {data}</div>
}
将 notifyOnChangeProps 选项设置为 ['data', 'error'],以便仅在选定的数据更改时重新渲染。
你是否希望可以在循环中运行 useQuery?Hook 的规则不允许这样做,但是有了新的 useQueries() Hook,你就可以做到了!
import { useQueries } from 'react-query'
function Overview() {
const results = useQueries([
{ queryKey: ['post', 1], queryFn: fetchPost },
{ queryKey: ['post', 2], queryFn: fetchPost },
])
return (
<ul>
{results.map(({ data }) => data && <li key={data.id}>{data.title})</li>)}
</ul>
)
}
import { useQueries } from 'react-query'
function Overview() {
const results = useQueries([
{ queryKey: ['post', 1], queryFn: fetchPost },
{ queryKey: ['post', 2], queryFn: fetchPost },
])
return (
<ul>
{results.map(({ data }) => data && <li key={data.id}>{data.title})</li>)}
</ul>
)
}
默认情况下,React Query 不会在错误时重试 mutation,但是可以使用 retry 选项来实现重试。
const mutation = useMutation({
mutationFn: addTodo,
retry: 3,
})
const mutation = useMutation({
mutationFn: addTodo,
retry: 3,
})
如果 mutation 因为设备离线而失败,当设备重新连接时,它们将按照相同的顺序重试。
现在可以将 mutation 持久化到存储并在稍后恢复。更多信息可以在 mutation 文档中找到。
可以使用 QueryObserver 来创建和/或监视一个 query
const observer = new QueryObserver(queryClient, { queryKey: 'posts' })
const unsubscribe = observer.subscribe((result) => {
console.log(result)
unsubscribe()
})
const observer = new QueryObserver(queryClient, { queryKey: 'posts' })
const unsubscribe = observer.subscribe((result) => {
console.log(result)
unsubscribe()
})
可以使用 InfiniteQueryObserver 来创建和/或监视一个无限 query
const observer = new InfiniteQueryObserver(queryClient, {
queryKey: 'posts',
queryFn: fetchPosts,
getNextPageParam: (lastPage, allPages) => lastPage.nextCursor,
getPreviousPageParam: (firstPage, allPages) => firstPage.prevCursor,
})
const unsubscribe = observer.subscribe((result) => {
console.log(result)
unsubscribe()
})
const observer = new InfiniteQueryObserver(queryClient, {
queryKey: 'posts',
queryFn: fetchPosts,
getNextPageParam: (lastPage, allPages) => lastPage.nextCursor,
getPreviousPageParam: (firstPage, allPages) => firstPage.prevCursor,
})
const unsubscribe = observer.subscribe((result) => {
console.log(result)
unsubscribe()
})
可以使用 QueriesObserver 来创建和/或监视多个 query
const observer = new QueriesObserver(queryClient, [
{ queryKey: ['post', 1], queryFn: fetchPost },
{ queryKey: ['post', 2], queryFn: fetchPost },
])
const unsubscribe = observer.subscribe((result) => {
console.log(result)
unsubscribe()
})
const observer = new QueriesObserver(queryClient, [
{ queryKey: ['post', 1], queryFn: fetchPost },
{ queryKey: ['post', 2], queryFn: fetchPost },
])
const unsubscribe = observer.subscribe((result) => {
console.log(result)
unsubscribe()
})
可以使用 QueryClient.setQueryDefaults() 方法为特定的 query 设置默认选项
queryClient.setQueryDefaults(['posts'], { queryFn: fetchPosts })
function Component() {
const { data } = useQuery(['posts'])
}
queryClient.setQueryDefaults(['posts'], { queryFn: fetchPosts })
function Component() {
const { data } = useQuery(['posts'])
}
可以使用 QueryClient.setMutationDefaults() 方法为特定的 mutation 设置默认选项
queryClient.setMutationDefaults(['addPost'], { mutationFn: addPost })
function Component() {
const { mutate } = useMutation({ mutationKey: ['addPost'] })
}
queryClient.setMutationDefaults(['addPost'], { mutationFn: addPost })
function Component() {
const { mutate } = useMutation({ mutationKey: ['addPost'] })
}
useIsFetching() Hook 现在接受过滤器,例如可以使用它仅为特定类型的 query 显示加载指示器
const fetches = useIsFetching({ queryKey: ['posts'] })
const fetches = useIsFetching({ queryKey: ['posts'] })
React Query 的核心现在已完全从 React 中分离出来,这意味着它也可以独立使用或在其他框架中使用。使用 react-query/core 入口点仅导入核心功能
import { QueryClient } from 'react-query/core'
import { QueryClient } from 'react-query/core'
devtools 现在包含在 react-query 包本身中,导入路径为 react-query/devtools。只需将 react-query-devtools 导入替换为 react-query/devtools