查询
一个 GraphQL 查询 是您想从 GraphQL 服务器查询数据的描述。它包含一组字段(以及可能的 片段),我们希望从 GraphQL 服务器请求这些字段。我们可以查询的内容将取决于服务器上公开的 GraphQL 架构,它描述了可用于查询的数据。
查询可以作为请求通过网络发送,并附带可选的 变量 集合,查询使用这些变量来获取数据。服务器响应将是一个与我们发送的查询形状匹配的 JSON 对象。
query UserQuery($id: ID!) {
user(id: $id) {
id
name
...UserFragment
}
viewer {
actor {
name
}
}
}
fragment UserFragment on User {
username
}
示例响应
{
"data": {
"user": {
"id": "4",
"name": "Mark Zuckerberg",
"username": "zuck"
},
"viewer": {
"actor": {
"name": "Your Name"
}
}
}
}
渲染查询
要渲染 Relay 中的查询,您可以使用 usePreloadedQuery
钩子。usePreloadedQuery
接受一个查询定义和一个查询引用,并返回该查询和引用的相应数据。
import type {HomeTabQuery} from 'HomeTabQuery.graphql';
import type {PreloadedQuery} from 'react-relay';
const React = require('React');
const {graphql, usePreloadedQuery} = require('react-relay');
type Props = {
queryRef: PreloadedQuery<HomeTabQuery>,
};
function HomeTab(props: Props) {
const data = usePreloadedQuery(
graphql`
query HomeTabQuery($id: ID!) {
user(id: $id) {
name
}
}
`,
props.queryRef,
);
return (
<h1>{data.user?.name}</h1>
);
}
让我们看看这里发生了什么
usePreloadedQuery
接受一个graphql
查询和一个PreloadedQuery
引用,并返回为该查询获取的数据。PreloadedQuery
(在本例中为queryRef
)是一个描述和引用正在(或已经)获取的查询实例的对象。- 我们将在下一节中介绍如何实际获取查询,并在 带有 Suspense 的加载状态 部分中介绍如何在尝试渲染查询时显示加载状态。
- 与 片段 类似,组件会自动订阅查询数据更新:如果此查询的数据在应用程序中的任何位置更新,则组件将自动使用最新更新的数据重新渲染。
usePreloadedQuery
还接受一个 Flow 类型参数,它对应于查询的 Flow 类型,在本例中为HomeTabQuery
。- Relay 编译器会自动为任何声明的查询生成 Flow 类型,您可以从以下名称格式的生成文件中导入这些类型:
<query_name>
.graphql.js
。 - 请注意,
data
已经正确地使用 Flow 类型化,无需显式注释,并且基于 GraphQL 架构中的类型。例如,上面data
的类型将是:{ user: ?{ name: ?string } }
。
- Relay 编译器会自动为任何声明的查询生成 Flow 类型,您可以从以下名称格式的生成文件中导入这些类型:
- 确保您在尝试渲染查询之前,使用 Relay 环境提供程序 在应用程序的根目录提供 Relay 环境。
获取用于渲染的查询
除了渲染查询之外,我们还需要从服务器获取它。通常情况下,我们希望在应用程序的根目录获取查询,并且只拥有一个或几个查询 累积 渲染屏幕所需的所有数据。理想情况下,我们应该尽早获取它们,甚至在开始渲染应用程序之前就获取它们。
为了获取查询以便稍后渲染它,您可以使用 useQueryLoader
钩子
import type {HomeTabQuery as HomeTabQueryType} from 'HomeTabQuery.graphql';
import type {PreloadedQuery} from 'react-relay';
const HomeTabQuery = require('HomeTabQuery.graphql')
const {useQueryLoader} = require('react-relay');
type Props = {
initialQueryRef: PreloadedQuery<HomeTabQueryType>,
};
function AppTabs(props) {
const [
homeTabQueryRef,
loadHomeTabQuery,
] = useQueryLoader(
HomeTabQuery,
props.initialQueryRef, /* e.g. provided by router */
);
const onSelectHomeTab = () => {
// Start loading query for HomeTab immediately in the event handler
// that triggers navigation to that tab, *before* we even start
// rendering the target tab.
// Calling this function will update the value of homeTabQueryRef.
loadHomeTabQuery({id: '4'});
// ...
}
// ...
return (
screen === 'HomeTab' && homeTabQueryRef != null ?
// Pass to component that uses usePreloadedQuery
<HomeTab queryRef={homeTabQueryRef} /> :
// ...
);
}
上面的例子有点牵强,但让我们提炼一下正在发生的事情
- 我们在
AppTabs
组件中调用useQueryLoader
。- 它接受一个查询,在本例中为
HomeTabQuery
(我们在前面的示例中声明的查询),我们可以通过以下方式获取它:'HomeTabQuery.graphql'
。 - 它接受一个可选的初始
PreloadedQuery
,作为存储在状态中并由useQueryLoader
返回的homeTabQueryRef
的初始值使用。 - 它还额外接受一个 Flow 类型参数,它对应于查询的 Flow 类型,在本例中为
HomeTabQueryType
,您也可以从自动生成的文件中获取它:'HomeTabQuery.graphql'
。
- 它接受一个查询,在本例中为
- 调用
useQueryLoader
使我们能够获得两件事homeTabQueryRef
:一个?PreloadedQuery
,它是一个描述和引用正在(或已经)获取的查询实例的对象。如果我们还没有获取查询,即如果我们还没有调用loadHomeTabQuery
,则此值将为 null。loadHomeTabQuery
:一个将获取此查询数据(如果它尚未缓存)并提供包含查询期望的 变量 的对象的函数,在本例中为{id: '4'}
(我们将在 重用缓存数据进行渲染 部分详细介绍 Relay 如何使用缓存数据)。调用此函数也将更新homeTabQueryRef
的值,使其成为PreloadedQuery
的实例。- 请注意,我们传递给此函数的
variables
将由 Flow 检查,以确保您传递的值与 GraphQL 查询期望的值匹配。 - 还要注意,我们是在导致渲染
HomeTab
的事件处理程序中调用此函数的。这使我们能够尽早开始获取屏幕数据,甚至在新的选项卡开始渲染之前就开始获取数据。- 事实上,
loadQuery
如果在 React 的渲染阶段调用,将会抛出错误!
- 事实上,
- 请注意,我们传递给此函数的
- 请注意,
useQueryLoader
将在组件卸载时自动处理所有已加载的查询。处理查询意味着 Relay 将不再在缓存中保存该特定查询实例的数据(我们将在 重用缓存数据进行渲染 部分介绍查询数据的生命周期)。此外,如果查询的请求在处理时仍在进行中,则该请求将被取消。 - 我们的
AppTabs
组件渲染前面示例中的HomeTab
组件,并将相应的查询引用传递给它。请注意,此父组件拥有该查询数据的生命周期,这意味着当它卸载时,它将处理该查询,如上所述。 - 最后,确保您在尝试使用
useQueryLoader
之前,使用 Relay 环境提供程序 在应用程序的根目录提供 Relay 环境。
有时,您希望在父组件的上下文中之外启动获取操作,例如获取应用程序初始加载所需的数据。对于这些情况,您可以直接使用 loadQuery
API,而不使用 useQueryLoader
import type {HomeTabQuery as HomeTabQueryType} from 'HomeTabQuery.graphql';
const HomeTabQuery = require('HomeTabQuery.graphql')
const {loadQuery} = require('react-relay');
const environment = createEnvironment(...);
// At some point during app initialization
const initialQueryRef = loadQuery<HomeTabQueryType>(
environment,
HomeTabQuery,
{id: '4'},
);
// ...
// E.g. passing the initialQueryRef to the root component
render(<AppTabs initialQueryRef={initialQueryRef} initialTab={...} />)
- 在这个例子中,我们直接调用
loadQuery
函数来获取一个PreloadedQuery
实例,我们稍后可以将其传递给使用usePreloadedQuery
的组件。 - 在本例中,我们希望根
AppTabs
组件管理查询引用的生命周期,并在适当的时候处理它,如果需要的话。 - 我们在这个例子中对“应用程序初始化”的细节含糊其词,因为这在不同的应用程序中会有所不同。这里需要注意的重要一点是,我们应该在开始渲染根组件之前获取查询引用。事实上,
loadQuery
如果在 React 的渲染阶段调用,将会抛出错误!
边获取边渲染
上面的例子说明了如何将获取数据与渲染数据分开,以便尽早开始获取操作(而不是等到组件渲染完成才开始获取操作),并使我们能够更早地向用户显示内容。它还有助于防止瀑布式往返操作,并且让我们可以更好地控制和预测获取操作何时发生,而如果我们在渲染期间进行获取操作,则更难确定获取操作何时会(或应该)发生。这与 “边获取边渲染” 模式与 React Suspense 非常吻合。
这是使用 Relay 获取数据的首选模式,它适用于多种情况,例如应用程序的初始加载、后续导航,或者通常情况下使用最初隐藏并在交互后显示的 UI 元素(如菜单、弹出窗口、对话框等),这些元素也需要获取其他数据。
在渲染期间延迟获取查询
获取查询的另一种选择是在组件渲染时延迟获取查询。但是,正如我们之前提到的,首选模式是在渲染之前开始获取查询。如果在没有谨慎的情况下使用延迟获取,它可能会触发嵌套或瀑布式往返操作,并可能降低性能。
要延迟获取查询,您可以使用 useLazyLoadQuery
钩子
const React = require('React');
const {graphql, useLazyLoadQuery} = require('react-relay');
function App() {
const data = useLazyLoadQuery(
graphql`
query AppQuery($id: ID!) {
user(id: $id) {
name
}
}
`,
{id: '4'},
);
return (
<h1>{data.user?.name}</h1>
);
}
让我们看看这里发生了什么
useLazyLoadQuery
接受一个 graphql 查询和一些该查询的变量,并返回为该查询获取的数据。变量是一个包含 GraphQL 查询中引用的 变量 值的对象。- 与 片段 类似,组件会自动订阅查询数据更新:如果此查询的数据在应用程序中的任何位置更新,则组件将自动使用最新更新的数据重新渲染。
useLazyLoadQuery
还额外接受一个 Flow 类型参数,它对应于查询的 Flow 类型,在本例中为 AppQuery。- 请记住,Relay 会自动为任何声明的查询生成 Flow 类型,您可以使用
useLazyLoadQuery
导入和使用这些类型。这些类型可以在以下名称格式的生成文件中找到:<query_name>.graphql.js
。 - 请注意,
variables
将由 Flow 检查,以确保您传递的值与 GraphQL 查询期望的值匹配。 - 请注意,
data
已经正确地使用 Flow 类型化,无需显式注释,并且基于 GraphQL 架构中的类型。例如,上面data
的类型将是:{ user: ?{ name: ?string } }
。
- 请记住,Relay 会自动为任何声明的查询生成 Flow 类型,您可以使用
- 默认情况下,当组件渲染时,Relay 会获取此查询的数据(如果它还没有被缓存),并将其作为
useLazyLoadQuery
调用的结果返回。我们将在使用 Suspense 的加载状态部分详细介绍如何显示加载状态,以及 Relay 如何在重用缓存数据进行渲染部分中使用缓存数据。 - 请注意,如果您重新渲染组件并传递不同的查询变量,与最初使用的变量不同,它将导致查询使用新的变量再次被获取,并且可能使用不同的数据重新渲染。
- 最后,在尝试渲染查询之前,请确保您在应用程序的根目录中使用Relay 环境提供程序提供了一个 Relay 环境。
此页面是否有用?
通过以下方式帮助我们改进网站: 回答几个简短的问题.