使用不同数据重新获取查询
当提到“重新获取查询”时,我们的意思是再次获取查询以获取与最初由查询呈现的不同数据。例如,这可能是为了更改当前选择的项目,渲染与正在显示的列表不同的项目列表,或者更一般地将当前呈现的内容转换为显示新的或不同的内容。
使用 useQueryLoader
/ loadQuery
与 使用 useQueryLoader
刷新查询 类似,我们也可以使用我们 渲染查询获取 部分中描述的 useQueryLoader
Hook,但这次传入不同的查询变量
/**
* App.react.js
*/
const AppQuery = require('__generated__/AppQuery.graphql');
function App(props: Props) {
const variables = {id: '4'};
const [queryRef, loadQuery] = useQueryLoader(
AppQuery,
props.appQueryRef /* initial query ref */
);
const refetch = useCallback(() => {
// Load the query again using the same original variables.
// Calling loadQuery will update the value of queryRef.
loadQuery({id: 'different-id'});
}, [/* ... */]);
return (
<React.Suspense fallback="Loading query...">
<MainContent
refetch={refetch}
queryRef={queryRef}
/>
</React.Suspense>
);
}
/**
* MainContent.react.js
*/
// Renders the preloaded query, given the query reference
function MainContent(props) {
const {refetch, queryRef} = props;
const data = usePreloadedQuery(
graphql`
query AppQuery($id: ID!) {
user(id: $id) {
name
friends {
count
}
}
}
`,
queryRef,
);
return (
<>
<h1>{data.user?.name}</h1>
<div>Friends count: {data.user?.friends?.count}</div>
<Button
onClick={() => refetch()}>
Fetch latest count
</Button>
</>
);
}
让我们分析一下这里发生了什么
- 我们在重新获取的事件处理程序中调用
loadQuery
,因此网络请求会立即开始,然后将queryRef
传递给usePreloadedQuery
,以便它呈现更新后的数据。 - 我们没有向
loadQuery
传递fetchPolicy
,这意味着它将使用默认值'store-or-network'
。我们可以提供不同的策略来指定是否使用本地缓存数据(正如我们在 重新使用缓存数据进行渲染 中所述)。 - 调用
loadQuery
将重新渲染组件,并可能导致usePreloadedQuery
挂起(如 使用 Suspense 的加载状态 中所述)。这意味着我们需要确保有一个Suspense
边界包装MainContent
组件,以便显示备用加载状态。
如果你需要避免 Suspense
在某些情况下,你可能希望避免显示 Suspense 备用,这将隐藏已经渲染的内容。对于这些情况,你可以使用 fetchQuery
而不是,并手动跟踪加载状态
注意
在 React 的未来版本中,当支持并发渲染时,React 将提供一个选项来支持这种情况,并在挂起时避免使用 Suspense 备用隐藏已经渲染的内容。
/**
* App.react.js
*/
const AppQuery = require('__generated__/AppQuery.graphql');
function App(props: Props) {
const environment = useRelayEnvironment();
const [queryRef, loadQuery] = useQueryLoader(
AppQuery,
props.appQueryRef /* initial query ref */
);
const [isRefetching, setIsRefetching] = useState(false)
const refetch = useCallback(() => {
if (isRefetching) { return; }
setIsRefetching(true);
// fetchQuery will fetch the query and write
// the data to the Relay store. This will ensure
// that when we re-render, the data is already
// cached and we don't suspend
fetchQuery(environment, AppQuery, variables)
.subscribe({
complete: () => {
setIsRefetching(false);
// *After* the query has been fetched, we call
// loadQuery again to re-render with a new
// queryRef.
// At this point the data for the query should
// be cached, so we use the 'store-only'
// fetchPolicy to avoid suspending.
loadQuery({id: 'different-id'}, {fetchPolicy: 'store-only'});
},
error: () => {
setIsRefetching(false);
}
});
}, [/* ... */]);
return (
<React.Suspense fallback="Loading query...">
<MainContent
isRefetching={isRefetching}
refetch={refetch}
queryRef={queryRef}
/>
</React.Suspense>
);
}
让我们分析一下这里发生了什么
- 在重新获取时,我们现在会跟踪我们自己的
isRefetching
加载状态,因为我们正在避免挂起。我们可以使用此状态在MainContent
组件内渲染一个忙碌的微调器或类似的加载 UI,而不会隐藏MainContent
。 - 在事件处理程序中,我们首先调用
fetchQuery
,它将获取查询并将数据写入本地 Relay 存储。当fetchQuery
网络请求完成后,我们调用loadQuery
,以便获得一个更新的queryRef
,然后将其传递给usePreloadedQuery
以渲染更新后的数据,类似于之前的示例。 - 此时,当调用
loadQuery
时,查询的数据应该已经被缓存到本地 Relay 存储中,因此我们使用fetchPolicy
的'store-only'
来避免挂起,并且只读取已经缓存的数据。
使用 useLazyLoadQuery
与 使用 useLazyLoadQuery
刷新查询 类似,我们也可以使用我们 useLazyLoadQuery
部分中描述的 渲染期间延迟获取查询 Hook,但这次传入不同的查询变量
/**
* App.react.js
*/
const AppQuery = require('__generated__/AppQuery.graphql');
function App(props: Props) {
const [queryArgs, setQueryArgs] = useState({
options: {fetchKey: 0},
variables: {id: '4'},
});
const refetch = useCallback(() => {
// Trigger a re-render of useLazyLoadQuery with new variables,
// *and* an updated fetchKey.
// The new fetchKey will ensure that the query is fully
// re-evaluated and refetched.
setQueryArgs(prev => ({
options: {
fetchKey: (prev?.options.fetchKey ?? 0) + 1,
},
variables: {id: 'different-id'}
}));
}, [/* ... */]);
return (
<React.Suspense fallback="Loading query...">
<MainContent
refetch={refetch}
queryArgs={queryArgs}
/>
</React.Suspense>
);
}
/**
* MainContent.react.js
*/
// Fetches and renders the query, given the fetch options
function MainContent(props) {
const {refetch, queryArgs} = props;
const data = useLazyLoadQuery(
graphql`
query AppQuery($id: ID!) {
user(id: $id) {
name
friends {
count
}
}
}
`,
queryArgs.variables,
queryArgs.options,
);
return (
<>
<h1>{data.user?.name}</h1>
<div>Friends count: {data.user.friends?.count}</div>
<Button
onClick={() => refetch()}>
Fetch latest count
</Button>
</>
);
}
让我们分析一下这里发生了什么
- 我们在重新获取的事件处理程序中更新组件,方法是在状态中设置新的查询参数。这将导致使用
useLazyLoadQuery
的MainContent
组件使用新的variables
和fetchKey
重新渲染,并在渲染时重新获取查询。 - 我们传递了一个新的
fetchKey
值,我们在每次更新时都会递增它。在每次更新时向useLazyLoadQuery
传递一个新的fetchKey
将确保查询被完全重新评估和重新获取。 - 我们没有向
useLazyLoadQuery
传递新的fetchPolicy
,这意味着它将使用默认值'store-or-network'
。我们可以提供不同的策略来指定是否使用本地缓存数据(正如我们在 重新使用缓存数据进行渲染 中所述)。 refetch
中的状态更新将重新渲染组件,并可能导致组件挂起(如 使用 Suspense 的加载状态 中所述)。这意味着我们需要确保有一个Suspense
边界包装MainContent
组件,以便显示备用加载状态。
如果你需要避免 Suspense
在某些情况下,你可能希望避免显示 Suspense 备用,这将隐藏已经渲染的内容。对于这些情况,你可以使用 fetchQuery
而不是,并手动跟踪加载状态
注意
在 React 的未来版本中,当支持并发渲染时,React 将提供一个选项来支持这种情况,并在挂起时避免使用 Suspense 备用隐藏已经渲染的内容。
/**
* App.react.js
*/
const AppQuery = require('__generated__/AppQuery.graphql');
function App(props: Props) {
const environment = useRelayEnvironment();
const [isRefreshing, setIsRefreshing] = useState(false)
const [queryArgs, setQueryArgs] = useState({
options: {fetchKey: 0, fetchPolicy: 'store-or-network'},
variables: {id: '4'},
});
const refetch = useCallback(() => {
if (isRefreshing) { return; }
setIsRefreshing(true);
// fetchQuery will fetch the query and write
// the data to the Relay store. This will ensure
// that when we re-render, the data is already
// cached and we don't suspend
fetchQuery(environment, AppQuery, variables)
.subscribe({
complete: () => {
setIsRefreshing(false);
// *After* the query has been fetched, we update
// our state to re-render with the new fetchKey
// and fetchPolicy.
// At this point the data for the query should
// be cached, so we use the 'store-only'
// fetchPolicy to avoid suspending.
setQueryArgs(prev => ({
options: {
fetchKey: (prev?.options.fetchKey ?? 0) + 1,
fetchPolicy: 'store-only',
},
variables: {id: 'different-id'}
}));
},
error: () => {
setIsRefreshing(false);
}
});
}, [/* ... */]);
return (
<React.Suspense fallback="Loading query...">
<MainContent
isRefetching={isRefetching}
refetch={refetch}
queryArgs={queryArgs}
/>
</React.Suspense>
);
}
让我们分析一下这里发生了什么
- 在重新获取时,我们现在会跟踪我们自己的
isRefetching
加载状态,因为我们正在避免挂起。我们可以使用此状态在MainContent
组件内渲染一个忙碌的微调器或类似的加载 UI,而不会隐藏MainContent
。 - 在事件处理程序中,我们首先调用
fetchQuery
,它将获取查询并将数据写入本地 Relay 存储。当fetchQuery
网络请求完成后,我们更新状态,以便我们重新渲染一个更新的fetchKey
和fetchPolicy
,然后将其传递给useLazyLoadQuery
以渲染更新后的数据,类似于之前的示例。 - 此时,当我们更新状态时,查询的数据应该已经被缓存到本地 Relay 存储中,因此我们使用
fetchPolicy
的'store-only'
来避免挂起,并且只读取已经缓存的数据。
此页面是否有用?
请帮助我们通过以下方式使网站变得更好 回答一些简短的问题.