useQueries
的新 APInotifyOnChangeProps
属性不再接受 "tracked"
作为值notifyOnChangePropsExclusion
cancelRefetch
的一致行为setQueryData
不再调用 onSuccess
persistQueryClient
和相应的 persister 插件不再是实验性的,并且已重命名cancel
方法不再受支持setLogger
queryClient
, query
和 mutation
中移除了未文档化的方法src/react
目录已重命名为 src/reactjs
v4 是一个主版本,因此有一些重大更改需要注意
您需要卸载/安装依赖项并更改导入
npm uninstall react-query
npm install @tanstack/react-query
npm install @tanstack/react-query-devtools
npm uninstall react-query
npm install @tanstack/react-query
npm install @tanstack/react-query-devtools
- import { useQuery } from 'react-query' // [!code --]
- import { ReactQueryDevtools } from 'react-query/devtools' // [!code --]
+ import { useQuery } from '@tanstack/react-query' // [!code ++]
+ import { ReactQueryDevtools } from '@tanstack/react-query-devtools' // [!code ++]
- import { useQuery } from 'react-query' // [!code --]
- import { ReactQueryDevtools } from 'react-query/devtools' // [!code --]
+ import { useQuery } from '@tanstack/react-query' // [!code ++]
+ import { ReactQueryDevtools } from '@tanstack/react-query-devtools' // [!code ++]
为了简化导入迁移,v4 提供了一个代码转换工具。
该代码转换工具是尽最大努力帮助您迁移重大更改的尝试。请仔细审查生成的代码!此外,代码转换工具无法找到一些边缘情况,因此请留意日志输出。
您可以通过使用以下一个或两个命令轻松应用它
如果您想针对 .js 或 .jsx 文件运行它,请使用以下命令
npx jscodeshift ./path/to/src/ \
--extensions=js,jsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/replace-import-specifier.js
npx jscodeshift ./path/to/src/ \
--extensions=js,jsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/replace-import-specifier.js
如果您想针对 .ts 或 .tsx 文件运行它,请使用以下命令
npx jscodeshift ./path/to/src/ \
--extensions=ts,tsx \
--parser=tsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/replace-import-specifier.js
npx jscodeshift ./path/to/src/ \
--extensions=ts,tsx \
--parser=tsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/replace-import-specifier.js
请注意,对于 TypeScript,您需要使用 tsx 作为解析器;否则,代码转换工具将无法正确应用!
注意: 应用代码转换工具可能会破坏您的代码格式,因此在应用代码转换工具后,请不要忘记运行 prettier 和/或 eslint!
注意: 代码转换工具仅会更改导入 - 您仍然需要手动安装单独的 devtools 包。
在 v3 中,Query 和 Mutation Keys 可以是字符串或数组。在内部,React Query 一直只使用数组键,并且我们有时会将其暴露给消费者。例如,在 queryFn 中,您总是会收到一个数组形式的键,以便更容易地使用 默认查询函数。
但是,我们并未将此概念应用到所有 API。例如,在使用 predicate 函数进行 查询过滤 时,您会收到原始的 Query Key。如果您使用的 Query Keys 是混合数组和字符串,这将使得处理这些函数变得困难。在使用全局回调时也是如此。
为了统一所有 API,我们决定只允许使用数组作为键
;-useQuery('todos', fetchTodos) + // [!code --]
useQuery(['todos'], fetchTodos) // [!code ++]
;-useQuery('todos', fetchTodos) + // [!code --]
useQuery(['todos'], fetchTodos) // [!code ++]
为了简化这次迁移,我们决定提供一个代码转换工具。
该代码转换工具是尽最大努力帮助您迁移重大更改的尝试。请仔细审查生成的代码!此外,代码转换工具无法找到一些边缘情况,因此请留意日志输出。
您可以通过使用以下一个或两个命令轻松应用它
如果您想针对 .js 或 .jsx 文件运行它,请使用以下命令
npx jscodeshift ./path/to/src/ \
--extensions=js,jsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/key-transformation.js
npx jscodeshift ./path/to/src/ \
--extensions=js,jsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/key-transformation.js
如果您想针对 .ts 或 .tsx 文件运行它,请使用以下命令
npx jscodeshift ./path/to/src/ \
--extensions=ts,tsx \
--parser=tsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/key-transformation.js
npx jscodeshift ./path/to/src/ \
--extensions=ts,tsx \
--parser=tsx \
--transform=./node_modules/@tanstack/react-query/codemods/v4/key-transformation.js
请注意,对于 TypeScript,您需要使用 tsx 作为解析器;否则,代码转换工具将无法正确应用!
注意: 应用代码转换工具可能会破坏您的代码格式,因此在应用代码转换工具后,请不要忘记运行 prettier 和/或 eslint!
随着新的 fetchStatus 的引入,以提供更好的离线支持,idle 状态变得无关紧要,因为 fetchStatus: 'idle' 更好地捕获了相同的状态。有关更多信息,请阅读 为什么需要两种不同的状态。
这主要会影响那些还没有 data 的 disabled 查询,因为它们以前处于 idle 状态
- status: 'idle' // [!code --]
+ status: 'loading' // [!code ++]
+ fetchStatus: 'idle' // [!code ++]
- status: 'idle' // [!code --]
+ status: 'loading' // [!code ++]
+ fetchStatus: 'idle' // [!code ++]
另外,请查看 关于依赖查询的指南
由于此更改,禁用的查询(即使是暂时禁用的)将从 loading 状态开始。为了简化迁移,特别是为了有一个良好的标志来知道何时显示加载微调器,您可以检查 isInitialLoading 而不是 isLoading
;-isLoading + // [!code --]
isInitialLoading // [!code ++]
;-isLoading + // [!code --]
isInitialLoading // [!code ++]
另请参阅关于 禁用查询 的指南
useQueries
的新 APIuseQueries
hook 现在接受一个带有 queries
prop 的对象作为输入。queries
prop 的值是一个查询数组(该数组与 v3 中传递给 useQueries
的内容相同)。
;-useQueries([
{ queryKey1, queryFn1, options1 },
{ queryKey2, queryFn2, options2 },
]) + // [!code --]
useQueries({
queries: [
{ queryKey1, queryFn1, options1 },
{ queryKey2, queryFn2, options2 },
],
}) // [!code ++]
;-useQueries([
{ queryKey1, queryFn1, options1 },
{ queryKey2, queryFn2, options2 },
]) + // [!code --]
useQueries({
queries: [
{ queryKey1, queryFn1, options1 },
{ queryKey2, queryFn2, options2 },
],
}) // [!code ++]
为了通过返回 undefined 来实现避免更新,我们将 undefined 设为不允许的缓存值。这与其他 react-query 的概念一致,例如,从 initialData 函数返回 undefined 也不会设置数据。
此外,通过在 queryFn 中添加日志记录,很容易产生 Promise<void> 的错误
useQuery(['key'], () =>
axios.get(url).then((result) => console.log(result.data)),
)
useQuery(['key'], () =>
axios.get(url).then((result) => console.log(result.data)),
)
这在类型级别上是不允许的;在运行时,undefined 将被转换为一个失败的 Promise,这意味着您将得到一个 error,在开发模式下也会将其记录到控制台。
请阅读关于在线/离线支持的 新功能公告,以及关于 网络模式 的专用页面
尽管 React Query 是一个异步状态管理器,可用于任何产生 Promise 的内容,但它最常用于与数据获取库结合的数据获取。因此,默认情况下,如果网络连接不可用,查询和突变将进入paused 状态。如果您想选择以前的行为,可以在全局范围内为查询和突变设置 networkMode: offlineFirst
new QueryClient({
defaultOptions: {
queries: {
networkMode: 'offlineFirst',
},
mutations: {
networkMode: 'offlineFirst',
},
},
})
new QueryClient({
defaultOptions: {
queries: {
networkMode: 'offlineFirst',
},
mutations: {
networkMode: 'offlineFirst',
},
},
})
notifyOnChangeProps
属性不再接受 "tracked" 作为值notifyOnChangeProps
选项不再接受 "tracked" 值。相反,useQuery 默认会跟踪属性。所有使用 notifyOnChangeProps: "tracked" 的查询都应通过移除此选项进行更新。
如果您想在任何查询中绕过此设置以模仿 v3 中每次查询更改时重新渲染的默认行为,notifyOnChangeProps 现在接受 "all" 值,以选择退出默认的智能跟踪优化。
在 v4 中,notifyOnChangeProps 默认使用 v3 的 "tracked" 行为,而不是 undefined。既然 "tracked" 是 v4 的默认行为,因此不再需要包含此配置选项。
cancelRefetch
的一致行为cancelRefetch
选项可以传递给所有以命令式方式获取查询的函数,即
refetch
fetchNextPage
和 fetchPreviousPage
除了 fetchNextPage 和 fetchPreviousPage 之外,此标志默认设置为 false,这不一致且可能带来麻烦:在突变后调用 refetchQueries 或 invalidateQueries 可能不会产生最新结果,因为先前的缓慢获取已在进行中,并且此重新获取将被跳过。
我们认为,如果您通过代码主动重新获取查询,它应该默认重新启动获取。
因此,此标志现在对上述所有方法都默认设置为true。这也意味着,如果您连续两次调用 refetchQueries 而不等待它,它将取消第一次获取并用第二次重新启动它
queryClient.refetchQueries({ queryKey: ['todos'] })
// this will abort the previous refetch and start a new fetch
queryClient.refetchQueries({ queryKey: ['todos'] })
queryClient.refetchQueries({ queryKey: ['todos'] })
// this will abort the previous refetch and start a new fetch
queryClient.refetchQueries({ queryKey: ['todos'] })
您可以显式传递 cancelRefetch:false 来选择退出此行为
queryClient.refetchQueries({ queryKey: ['todos'] })
// this will not abort the previous refetch - it will just be ignored
queryClient.refetchQueries({ queryKey: ['todos'] }, { cancelRefetch: false })
queryClient.refetchQueries({ queryKey: ['todos'] })
// this will not abort the previous refetch - it will just be ignored
queryClient.refetchQueries({ queryKey: ['todos'] }, { cancelRefetch: false })
注意:对于自动触发的获取,例如因为查询挂载或因为窗口焦点重新获取,行为没有改变。
一个 查询过滤器 是一个带有匹配查询条件的对象的。历史上,过滤器选项大部分是布尔标志的组合。然而,组合这些标志可能导致不可能的状态。具体来说
active?: boolean
- When set to true it will match active queries.
- When set to false it will match inactive queries.
inactive?: boolean
- When set to true it will match inactive queries.
- When set to false it will match active queries.
active?: boolean
- When set to true it will match active queries.
- When set to false it will match inactive queries.
inactive?: boolean
- When set to true it will match inactive queries.
- When set to false it will match active queries.
当这些标志一起使用时,它们效果不佳,因为它们是互斥的。根据描述,将两个标志都设置为 false 可能会匹配所有查询,或者不匹配任何查询,这没有多大意义。
在 v4 中,这些过滤器已合并为单个过滤器,以更好地显示意图
- active?: boolean // [!code --]
- inactive?: boolean // [!code --]
+ type?: 'active' | 'inactive' | 'all' // [!code ++]
- active?: boolean // [!code --]
- inactive?: boolean // [!code --]
+ type?: 'active' | 'inactive' | 'all' // [!code ++]
过滤器默认为 all,您可以选择只匹配 active 或 inactive 查询。
queryClient.invalidateQueries 还有两个额外的、类似的标志
refetchActive: Boolean
- Defaults to true
- When set to false, queries that match the refetch predicate and are actively being rendered
via useQuery and friends will NOT be refetched in the background, and only marked as invalid.
refetchInactive: Boolean
- Defaults to false
- When set to true, queries that match the refetch predicate and are not being rendered
via useQuery and friends will be both marked as invalid and also refetched in the background
refetchActive: Boolean
- Defaults to true
- When set to false, queries that match the refetch predicate and are actively being rendered
via useQuery and friends will NOT be refetched in the background, and only marked as invalid.
refetchInactive: Boolean
- Defaults to false
- When set to true, queries that match the refetch predicate and are not being rendered
via useQuery and friends will be both marked as invalid and also refetched in the background
出于相同的原因,这些也已合并
- refetchActive?: boolean // [!code --]
- refetchInactive?: boolean // [!code --]
+ refetchType?: 'active' | 'inactive' | 'all' | 'none' // [!code ++]
- refetchActive?: boolean // [!code --]
- refetchInactive?: boolean // [!code --]
+ refetchType?: 'active' | 'inactive' | 'all' | 'none' // [!code ++]
此标志默认为 active,因为 refetchActive 默认为 true。这意味着我们还需要一种方法来告知 invalidateQueries 完全不重新获取,这就是为什么这里也允许第四个选项(none)。
onSuccess
不再从 setQueryData
调用这让许多人感到困惑,并且当 setQueryData 从 onSuccess 中调用时,还会导致无限循环。当与 staleTime 结合使用时,这也是一个常见的错误源,因为如果数据仅从缓存读取,则不会调用 onSuccess。
与 onError 和 onSettled 类似,onSuccess 回调现在与请求的发出相关联。没有请求 -> 没有回调。
如果您想监听 data 字段的变化,最好使用 useEffect,其中 data 是依赖数组的一部分。由于 React Query 通过结构共享确保数据稳定,因此效果不会在每次后台重新获取时执行,而仅在数据中的某些内容发生更改时执行
const { data } = useQuery({ queryKey, queryFn })
React.useEffect(() => mySideEffectHere(data), [data])
const { data } = useQuery({ queryKey, queryFn })
React.useEffect(() => mySideEffectHere(data), [data])
persistQueryClient
和相应的 persister 插件不再是实验性的,并且已重命名插件 createWebStoragePersistor 和 createAsyncStoragePersistor 已分别重命名为 createSyncStoragePersister 和 createAsyncStoragePersistor。persistQueryClient
中的接口 Persistor 也已重命名为 Persister。请查看 此 stackexchange 以了解更改的动机。
由于这些插件不再是实验性的,它们的导入路径也已更新
- import { persistQueryClient } from 'react-query/persistQueryClient-experimental' // [!code --]
- import { createWebStoragePersistor } from 'react-query/createWebStoragePersistor-experimental' // [!code --]
- import { createAsyncStoragePersistor } from 'react-query/createAsyncStoragePersistor-experimental' // [!code --]
+ import { persistQueryClient } from '@tanstack/react-query-persist-client' // [!code ++]
+ import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister' // [!code ++]
+ import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister' // [!code ++]
- import { persistQueryClient } from 'react-query/persistQueryClient-experimental' // [!code --]
- import { createWebStoragePersistor } from 'react-query/createWebStoragePersistor-experimental' // [!code --]
- import { createAsyncStoragePersistor } from 'react-query/createAsyncStoragePersistor-experimental' // [!code --]
+ import { persistQueryClient } from '@tanstack/react-query-persist-client' // [!code ++]
+ import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister' // [!code ++]
+ import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister' // [!code ++]
cancel
方法不再受支持允许您在 Promises 上定义 cancel 函数的 旧 cancel 方法,然后由库用于支持查询取消,已被移除。我们建议使用(v3.30.0 引入的)新 API 来进行查询取消,该 API 内部使用 AbortController API,并为您提供一个 AbortSignal 实例供您的 queryFn 使用,以支持查询取消。
类型现在要求使用 TypeScript v4.1 或更高版本
从 v4 开始,React Query 针对现代浏览器进行了优化。我们更新了 browserslist 以生成更现代、性能更好、体积更小的包。您可以在 这里 阅读有关要求的信息。
setLogger
通过调用 setLogger 可以全局更改 logger。在 v4 中,该函数被创建 QueryClient 时的可选字段所取代。
- import { QueryClient, setLogger } from 'react-query'; // [!code --]
+ import { QueryClient } from '@tanstack/react-query'; // [!code ++]
- setLogger(customLogger) // [!code --]
- const queryClient = new QueryClient(); // [!code --]
+ const queryClient = new QueryClient({ logger: customLogger }) // [!code ++]
- import { QueryClient, setLogger } from 'react-query'; // [!code --]
+ import { QueryClient } from '@tanstack/react-query'; // [!code ++]
- setLogger(customLogger) // [!code --]
- const queryClient = new QueryClient(); // [!code --]
+ const queryClient = new QueryClient({ logger: customLogger }) // [!code ++]
在 v3 中,React Query 会默认缓存查询结果 5 分钟,然后手动进行垃圾回收。此默认值也适用于服务器端 React Query。
这导致内存消耗过高以及进程挂起等待此手动垃圾回收完成。在 v4 中,默认情况下,服务器端 cacheTime 现在设置为 Infinity,实际上禁用了手动垃圾回收(NodeJS 进程将在请求完成后清除所有内容)。
此更改仅影响服务器端 React Query 的用户,例如与 Next.js 一起使用。如果您手动设置了 cacheTime,这不会影响您(尽管您可能希望镜像行为)。
从 v4 开始,React Query 在生产模式下不再将错误(例如,失败的获取)记录到控制台,因为这让许多人感到困惑。错误仍然会在开发模式下显示。
React Query 现在支持 package.json "exports",并且完全兼容 Node 对 CommonJS 和 ESM 的原生解析。我们预计这对大多数用户来说都不是重大更改,但这会将您可以在项目中导入的文件限制为我们官方支持的入口点。
手动订阅 QueryCache 始终会为您提供一个 QueryCacheNotifyEvent,但 MutationCache 则不是。我们已简化了行为,并相应地调整了事件名称。
- type: 'queryAdded' // [!code --]
+ type: 'added' // [!code ++]
- type: 'queryRemoved' // [!code --]
+ type: 'removed' // [!code ++]
- type: 'queryUpdated' // [!code --]
+ type: 'updated' // [!code ++]
- type: 'queryAdded' // [!code --]
+ type: 'added' // [!code ++]
- type: 'queryRemoved' // [!code --]
+ type: 'removed' // [!code ++]
- type: 'queryUpdated' // [!code --]
+ type: 'updated' // [!code ++]
MutationCacheNotifyEvent
使用与 QueryCacheNotifyEvent
相同的类型。
注意:这仅与通过 queryCache.subscribe 或 mutationCache.subscribe 手动订阅缓存的用户相关
随着版本 3.22.0,hydration 工具已移至 React Query 核心。在 v3 中,您仍然可以使用来自 react-query/hydration 的旧导出,但这些导出在 v4 中已被移除。
- import { dehydrate, hydrate, useHydrate, Hydrate } from 'react-query/hydration' // [!code --]
+ import { dehydrate, hydrate, useHydrate, Hydrate } from '@tanstack/react-query' // [!code ++]
- import { dehydrate, hydrate, useHydrate, Hydrate } from 'react-query/hydration' // [!code --]
+ import { dehydrate, hydrate, useHydrate, Hydrate } from '@tanstack/react-query' // [!code ++]
queryClient
, query
和 mutation
中移除了未文档化的方法QueryClient
上的 cancelMutations 和 executeMutation 方法未进行文档化且在内部未使用,因此我们将其移除。由于它只是 mutationCache 上可用方法的一个包装器,您仍然可以使用 executeMutation 的功能
- executeMutation< // [!code --]
- TData = unknown, // [!code --]
- TError = unknown, // [!code --]
- TVariables = void, // [!code --]
- TContext = unknown // [!code --]
- >( // [!code --]
- options: MutationOptions<TData, TError, TVariables, TContext> // [!code --]
- ): Promise<TData> { // [!code --]
- return this.mutationCache.build(this, options).execute() // [!code --]
- } // [!code --]
- executeMutation< // [!code --]
- TData = unknown, // [!code --]
- TError = unknown, // [!code --]
- TVariables = void, // [!code --]
- TContext = unknown // [!code --]
- >( // [!code --]
- options: MutationOptions<TData, TError, TVariables, TContext> // [!code --]
- ): Promise<TData> { // [!code --]
- return this.mutationCache.build(this, options).execute() // [!code --]
- } // [!code --]
此外,query.setDefaultOptions 已被移除,因为它也没有被使用。mutation.cancel
已被移除,因为它实际上并未取消正在进行的请求。
src/react
目录已重命名为 src/reactjs
以前,React Query 有一个名为 react 的目录,它从 react 模块导入。这可能会导致某些 Jest 配置出现问题,从而在运行测试时出现错误,例如
TypeError: Cannot read property 'createContext' of undefined
TypeError: Cannot read property 'createContext' of undefined
随着目录的重命名,这个问题不再存在。
如果您直接在项目中从 'react-query/react' 导入任何内容(而不是仅从 'react-query' 导入),那么您需要更新您的导入
- import { QueryClientProvider } from 'react-query/react'; // [!code --]
+ import { QueryClientProvider } from '@tanstack/react-query/reactjs'; // [!code ++]
- import { QueryClientProvider } from 'react-query/react'; // [!code --]
+ import { QueryClientProvider } from '@tanstack/react-query/reactjs'; // [!code ++]
v4 带来了一系列很棒的新功能
React 18 于今年早些时候发布,v4 现在对其及其带来的新并发功能提供了一级支持。
在 v3 中,React Query 总是会触发查询和突变,但然后假定如果您想重试,您需要连接到互联网。这导致了许多令人困惑的情况
在 v4 中,React Query 引入了新的 networkMode 来解决所有这些问题。请阅读关于新 网络模式 的专用页面以获取更多信息。
React Query 默认“跟踪”查询属性,这应该能为您带来显著的渲染优化。该功能自 v3.6.0 以来一直存在,现在在 v4 中已成为默认行为。
在使用 setQueryData 的函数式更新器形式 时,您现在可以通过返回 undefined 来避免更新。如果 undefined 作为 previousValue 提供给您,这会很有帮助,这意味着当前没有缓存条目存在,并且您不想/无法创建它,例如在切换待办事项的示例中
queryClient.setQueryData(['todo', id], (previousTodo) =>
previousTodo ? { ...previousTodo, done: true } : undefined,
)
queryClient.setQueryData(['todo', id], (previousTodo) =>
previousTodo ? { ...previousTodo, done: true } : undefined,
)
与查询一样,突变现在也可以自动进行垃圾回收。突变的默认 cacheTime 也设置为 5 分钟。
现在可以指定自定义上下文,以将 hook 与其匹配的 Provider 配对。当组件树中可能存在多个 React Query Provider 实例时,这一点至关重要,您需要确保您的 hook 使用正确的 Provider 实例。
一个例子
// Our first data package: @my-scope/container-data
const context = React.createContext<QueryClient | undefined>(undefined)
const queryClient = new QueryClient()
export const useUser = () => {
return useQuery(USER_KEY, USER_FETCHER, {
context,
})
}
export const ContainerDataProvider = ({
children,
}: {
children: React.ReactNode
}) => {
return (
<QueryClientProvider client={queryClient} context={context}>
{children}
</QueryClientProvider>
)
}
// Our first data package: @my-scope/container-data
const context = React.createContext<QueryClient | undefined>(undefined)
const queryClient = new QueryClient()
export const useUser = () => {
return useQuery(USER_KEY, USER_FETCHER, {
context,
})
}
export const ContainerDataProvider = ({
children,
}: {
children: React.ReactNode
}) => {
return (
<QueryClientProvider client={queryClient} context={context}>
{children}
</QueryClientProvider>
)
}
// Our second data package: @my-scope/my-component-data
const context = React.createContext<QueryClient | undefined>(undefined)
const queryClient = new QueryClient()
export const useItems = () => {
return useQuery(ITEMS_KEY, ITEMS_FETCHER, {
context,
})
}
export const MyComponentDataProvider = ({
children,
}: {
children: React.ReactNode
}) => {
return (
<QueryClientProvider client={queryClient} context={context}>
{children}
</QueryClientProvider>
)
}
// Our second data package: @my-scope/my-component-data
const context = React.createContext<QueryClient | undefined>(undefined)
const queryClient = new QueryClient()
export const useItems = () => {
return useQuery(ITEMS_KEY, ITEMS_FETCHER, {
context,
})
}
export const MyComponentDataProvider = ({
children,
}: {
children: React.ReactNode
}) => {
return (
<QueryClientProvider client={queryClient} context={context}>
{children}
</QueryClientProvider>
)
}
// Our application
import { ContainerDataProvider, useUser } from "@my-scope/container-data";
import { AppDataProvider } from "@my-scope/app-data";
import { MyComponentDataProvider, useItems } from "@my-scope/my-component-data";
<ContainerDataProvider> // <-- Provides container data (like "user") using its own React Query provider
...
<AppDataProvider> // <-- Provides app data using its own React Query provider (unused in this example)
...
<MyComponentDataProvider> // <-- Provides component data (like "items") using its own React Query provider
<MyComponent />
</MyComponentDataProvider>
...
</AppDataProvider>
...
</ContainerDataProvider>
// Example of hooks provided by the "DataProvider" components above:
const MyComponent = () => {
const user = useUser() // <-- Uses the context specified in ContainerDataProvider.
const items = useItems() // <-- Uses the context specified in MyComponentDataProvider
...
}
// Our application
import { ContainerDataProvider, useUser } from "@my-scope/container-data";
import { AppDataProvider } from "@my-scope/app-data";
import { MyComponentDataProvider, useItems } from "@my-scope/my-component-data";
<ContainerDataProvider> // <-- Provides container data (like "user") using its own React Query provider
...
<AppDataProvider> // <-- Provides app data using its own React Query provider (unused in this example)
...
<MyComponentDataProvider> // <-- Provides component data (like "items") using its own React Query provider
<MyComponent />
</MyComponentDataProvider>
...
</AppDataProvider>
...
</ContainerDataProvider>
// Example of hooks provided by the "DataProvider" components above:
const MyComponent = () => {
const user = useUser() // <-- Uses the context specified in ContainerDataProvider.
const items = useItems() // <-- Uses the context specified in MyComponentDataProvider
...
}