HOC
已废弃的 React Apollo HOC API
注意:React Apollo HOC 的官方支持于 2020 年 3 月结束。此库仍包含在 @apollo/client 包中,但不再接收新功能和错误修复。
安装
此 HOC 库包含在核心 @apollo/client 包中:
npm install @apollo/client
然后从 @apollo/client/react/hoc 导入库的符号。
graphql(query, [config])(component)
import { graphql } from '@apollo/client/react/hoc';
该 graphql() 函数是 Apollo HOC API 的核心。使用此函数创建可以执行查询并根据您 Apollo store 中的数据动态更新的高阶组件。
`graphql()`函数返回一个函数,该函数可以为任何具有反应能力的组件提供“增强”功能。这遵循了React的高阶组件模式,该模式也被react-redux的`connect函数所使用。
如果您的组件中有一个集中的组件`<ApolloProvider/>ApolloClient实例来请求数据,则`graphql()`函数只能提供对您的GraphQL数据的访问。
使用`graphql()`函数增强的组件的行为将根据您的GraphQL操作的类型(查询、变更或订阅)而异。请参考相应API文档以了解更多关于每种类型的功能和选项的信息。
示例
您可以使用`graphql()`函数如下所示:
function TodoApp({ data: { todos } }) {return (<ul>{todos.map(({ id, text }) => (<li key={id}>{text}</li>))}</ul>);}export default graphql(gql`query TodoAppQuery {todos {idtext}}`)(TodoApp);
您还可以定义一个中间函数,并使用以下方式将组件与`graphql()`函数连接起来:
// Create our enhancer function.const withTodoAppQuery = graphql(gql`query TodoAppQuery { ... }`);// Enhance our component.const TodoAppWithData = withTodoAppQuery(TodoApp);// Export the enhanced component.export default TodoAppWithData;
配置对象
在我们具体查看每种操作的特定行为之前,让我们先来看看`config`对象。`config`对象是GraphQL文档之后的第二个参数,通过它您可以为高阶组件添加一些自定义行为`。`config`是可选的,允许您定义组件在处理GraphQL数据时应使用的特定行为。
export default graphql(gql`query MyQuery { ... }`,config, // <- The `config` object.)(MyComponent);
让我们来看看可能存在于您的`config`对象上的所有属性。
config.options
`config.options`是一个对象或函数,允许您定义组件处理GraphQL数据时应使用的特定行为。
可配置的具体选项取决于传递给graphql()函数的第一个参数(操作)。存在针对查询和突变的特定选项。
您可以将config.options定义为普通对象,或者您可以从接受组件属性作为参数的函数中计算选项。
示例
export default graphql(gql`query MyQuery { ... }`, {options: {// Options go here.},})(MyComponent);
export default graphql(gql`query MyQuery { ... }`, {options: props => ({// Options are computed from `props` here.}),})(MyComponent);
config.props
属性config.props允许您定义一个函数,它接受由graphql()函数添加的props(可选地包括lastProps),并为 GraphQL 查询的 props.data和props.mutate突变使用。
您定义的函数与 Recompose 的mapProps基本相同,提供相同的功能,而无需另一个库。
;config.props最有用之处在于,它可以抽象出复杂的函数调用到简单的属性中,您可以将这些属性传递到您的组件中。
;config.props的另一个好处是,它还可以帮助您将纯 UI 组件与 GraphQL 和 Apollo 的关注点分离。您可以在一个文件中编写纯 UI 组件,然后将与商店交互所需的逻辑保留在项目中完全不同的位置。您可以通过让纯 UI 组件仅请求用于渲染的属性来实现这一点,而config.props将包含从您的 GraphQL API 提供的数据中提供确切属性的逻辑。
示例
此示例使用 props.data.fetchMore
export default graphql(gql`query MyQuery { ... }`, {props: ({ data: { fetchMore } }) => ({onLoadMore: () => {fetchMore({ ... });},}),})(MyComponent);function MyComponent({ onLoadMore }) {return (<button onClick={onLoadMore}>Load More!</button>);}
要访问由graphql()函数未添加的属性,请使用ownProps关键字。例如:
export default graphql(gql`query MyQuery { ... }`, {props: ({ data: { liveImage }, ownProps: { loadingImage } }) => ({image: liveImage || loadingImage,}),})(MyComponent);
要访问lastProps,请使用config.props的第二个参数。例如:
export default graphql(gql`query MyQuery { ... }`, {props: ({ data: { liveImage } }, lastProps) => ({image: liveImage,lastImage: lastProps.data.liveImage,}),})(MyComponent);
config.skip
如果config.skip设置为true,则完全跳过所有 React Apollo 代码。您的组件将表现得就像graphql()函数根本不存在一样。
您还可以将一个函数传递给config.skip。如果这样做,该函数将接收到您的组件属性,并应该返回一个布尔值。如果该函数返回true,则跳过行为将生效。
config.skip特别有用,如果您想根据某些属性使用不同的查询。以下是一个示例。
示例
export default graphql(gql`query MyQuery { ... }`, {skip: props => !!props.skip,})(MyComponent);
以下示例使用compose函数一次使用多个graphql()增强器。
export default compose(graphql(gql`query MyQuery1 { ... }`, { skip: props => !props.useQuery1 }),graphql(gql`query MyQuery2 { ... }`, { skip: props => props.useQuery1 }),)(MyComponent);function MyComponent({ data }) {// The data may be from `MyQuery1` or `MyQuery2` depending on the value// of the prop `useQuery1`.console.log(data);}
config.name
此属性允许您配置传递到您的组件的prop的名称。默认情况下,如果传入GraphQL的文档是一个查询,则您的prop的名称为data。如果您传递了一个突变,则您的prop将命名为mutate。您使用多个具有相同组件的查询或突变时,这些默认名称将发生冲突。要避免冲突,请使用config.name来指定不同的名称。
示例
此示例使用compose函数一起使用多个graphql()高阶组件。
export default compose(graphql(gql`mutation CreateTodoMutation (...) { ... }`, { name: 'createTodo' }),graphql(gql`mutation UpdateTodoMutation (...) { ... }`, { name: 'updateTodo' }),graphql(gql`mutation DeleteTodoMutation (...) { ... }`, { name: 'deleteTodo' }),)(MyComponent);function MyComponent(props) {// Instead of the default prop name, `mutate`,// we have three different prop names.console.log(props.createTodo);console.log(props.updateTodo);console.log(props.deleteTodo);return null;}
config.withRef
将config.withRef设置为true,您可以使用存在于高阶GraphQL组件实例上的getWrappedInstance方法从您的包装组件中获取包装组件的实例。
当您想调用包装组件上的函数或访问属性时,您可能希望将其设置为true。
示例
此示例使用React 功能。ref
class MyComponent extends Component {saySomething() {console.log('Hello, world!');}render() {// ...}}const MyGraphQLComponent = graphql(gql`query MyQuery { ... }`, { withRef: true })(MyComponent,);class MyContainerComponent extends Component {render() {return (<MyGraphQLComponentref={component => {const wrappedInstance = component.getWrappedInstance();assert(wrappedInstance instanceof MyComponent);// We can call methods on the component class instance.wrappedInstance.saySomething();}}/>);}}
config.alias
使用此属性配置高阶组件包装器的名称。例如,如果您将config.alias设置为'withCurrentUser',则包装组件的显示名称变为withCurrentUser(${WrappedComponent.displayName})而不是Apollo(${WrappedComponent.displayName})。
React Apollo 组件的默认显示名称为 Apollo(${WrappedComponent.displayName})。这种模式被大多数使用高阶组件的 React 库所使用。然而,当你使用多个高阶组件时,这可能会变得混淆,尤其是当你查看 React Devtools。
示例
此示例使用compose函数一起使用多个graphql()高阶组件。
export default compose(graphql(gql`query MyQuery { ... }`, { alias: 'withCurrentUser' }),graphql(gql`query MyQuery { ... }`, { alias: 'withList' }),)(MyComponent);
查询的 graphql() 选项
props.data
使用 graphql() 创建的高阶组件会将 data 属性传递给您的组件。如下所示:
render() {const { data } = this.props; // <- The `data` prop.}
The data prop 包含从您的 query 检索到的数据,以及一些其他有用的信息和函数来控制您的 GraphQL 连接组件的生命周期。例如,如果我们有一个查询看起来像这样:
query ViewerAndTodos {viewer {name}todos {text}}
您的 data prop 会包含那些数据:
render() {const { data } = this.props;console.log(data.viewer); // <- The data returned by your query for `viewer`.console.log(data.todos); // <- The data returned by your query for `todos`.}
The data prop 还有一些其他有用的属性,可以直接从 data 访问。例如, data.loading 或 data.error。这些属性将在下面进行文档说明。
确保在渲染组件之前始终检查 data.loading 和 data.error。像 data.todos 这样的属性,它是您应用程序数据的容器,在组件执行初始获取时可能是未定义的。检查 data.loading 和 data.error 可以帮助您避免任何与未定义数据相关的问题。这样的检查可能看起来像:
render() {const { data: { loading, error, todos } } = this.props;if (loading) {return <p>Loading...</p>;}if (error) {return <p>Error!</p>;}return (<ul>{todos.map(({ id, text }) => (<li key={id}>{text}</li>))}</ul>);}
data.loading
一个布尔值,表示是否为该组件正在进行查询请求。这意味着已经使用您的网络接口发送了查询请求,我们尚未收到响应。使用此属性来渲染加载组件。
然而,仅因为 data.loading 是 true 并不代表你没有数据。例如,如果你已经有了 data.todos,但你想要从你的 API 中获取最新的 todos,那么 data.loading 可能是 true,但你仍然会从之前的请求中获取 todos。
你的查询可能处于多种不同的网络状态。如果你想更详细地了解你的组件的网络状态,请参阅 data.networkStatus。
示例
function MyComponent({ data: { loading } }) {if (loading) {return <div>Loading...</div>;} else {// ...}}export default graphql(gql`query MyQuery { ... }`)(MyComponent);
data.error
如果发生错误,则此属性将是 ApolloError 的一个实例。如果你没有处理此错误,你将在控制台中看到一个警告,类似于: "Unhandled (in react-apollo) Error: ..."。
示例
function MyComponent({ data: { error } }) {if (error) {return <div>Error!</div>;} else {// ...}}export default graphql(gql`query MyComponentQuery { ... }`)(MyComponent);
data.networkStatus
data.networkStatus 如果要显示不同的加载指示器(或根本不显示指示器),则非常有用,因为它提供了对组件网络请求状态的更详细视图,比 data.loading 更详细。 data.networkStatus 是一个枚举,编号在 1 到 8 之间。这些数字值分别表示不同的网络状态。
loading:查询从未运行过,请求现在挂起。查询即使从缓存中返回结果,但仍然发出请求,也将具有此网络状态。setVariables:如果查询的 变量 发生变化并发出网络请求,则网络状态将为setVariables,直到返回该查询的结果。React 用户将在他们的查询上修改options.variables时看到这一点。fetchMore:表示在此查询上调用fetchMore并正在处理创建的网络请求。refetch:这意味着在查询上调用refetch,且当前的重复请求正在处理中。- 未使用。
poll:表示正在执行轮询查询。例如,如果你每 10 秒轮询一次查询,那么每当轮询请求已经发送但未解决时,网络状态将每 10 秒切换到poll。ready:对此查询没有正在处理中的请求,且没有发生错误。一切正常。error:对此查询没有正在处理中的请求,但检测到一个或多个错误。
如果网络状态小于7,则与 data.loading 为真等效。实际上,您可以将所有 data.loading 检查替换为 data.networkStatus < 7 而不会看到任何区别。然而,建议您使用 data.loading。
示例
function MyComponent({ data: { networkStatus } }) {if (networkStatus === 6) {return <div>Polling!</div>;} else if (networkStatus < 7) {return <div>Loading...</div>;} else {// ...}}export default graphql(gql`query MyComponentQuery { ... }`)(MyComponent);
data.variables
Apollo从您的 GraphQL 网端获取数据所使用的 variables。如果您想根据用于请求服务器所用的变量来渲染一些信息,该属性会很有用。
示例
function MyComponent({ data: { variables } }) {return (<div>Query executed with the following variables:<code>{JSON.stringify(variables)}</code></div>);}export default graphql(gql`query MyComponentQuery { ... }`)(MyComponent);
data.refetch(variables)
强制您的组件重新查询在 graphql() 函数中定义的 查询。当您想要重新加载数据或尝试在发生错误后重新获取数据时,该方法很有用。
data.refetch 返回一个承诺,一旦 查询 执行完成后,承诺将解决为从您的 API 获取的新数据。如果查询失败,则承诺将拒绝。
data.refetch 函数接受一个单一的 variables 对象参数。 variables 参数将替换与 query 选项或从您的 graphql() HOC 中获取的 query 一起使用的 variables(根据您是否指定了 query 选项来重新查询 query)。
示例
function MyComponent({ data: { refetch } }) {return <button onClick={() => refetch()}>Reload</button>;}export default graphql(gql`query MyComponentQuery { ... }`)(MyComponent);
data.fetchMore(options)
data.fetchMore 函数允许您使用 查询 组件进行分页。要了解更多关于 data.fetchMore 的分页信息,请务必阅读 分页文档。
data.fetchMore 返回一个承诺,在执行以获取更多数据的 查询 解决后,将解决。
data.fetchMore 函数接受一个单一的 options 对象参数。 options 参数可能具有以下属性:
[query]:这是一个可选的 GraphQL 文档,使用gql标记创建。如果指定了query,则在调用data.fetchMore时将获取该query。如果没有指定query,则将使用graphql()HOC 中定义的query。[variables]:可以提供的可选变量,可用于query选项或您的graphql()HOC 从中获取的query(根据是否指定了query)。updateQuery(previousResult, { fetchMoreResult, variables }): 这是您必须定义的一个函数,用于实际更新您的分页列表。第一个参数previousResult是指您在graphql()函数中定义的查询返回的前一个数据。第二个参数是一个包含两个属性的对象,即fetchMoreResult和variables。其中,fetchMoreResult是指使用从data.fetchMore中提供的query和variables选项进行的新获取的数据。变量variables是指在获取更多数据时使用的变量。使用这些参数,您应该返回一个与您在graphql()函数中定义的GraphQL查询具有相同形状的新数据对象。下面是一个示例,并确保阅读有关分页文档的更多信息。。
示例
data.fetchMore({updateQuery: (previousResult, { fetchMoreResult, variables }) => {return {...previousResult,// Add the new feed data to the end of the old feed data.feed: [...previousResult.feed, ...fetchMoreResult.feed],};},});
data.subscribeToMore(options)
这个函数将在每次服务器发送订阅发布时触发更新,设置一个订阅。要正常工作,服务器上需要设置订阅。有关如何设置此信息的更多信息,请参阅订阅指南。
此函数返回一个unsubscribe函数处理程序,可稍后用于取消订阅。
一个常见的做法是在getDerivedStateFromProps中将subscribeToMore调用包裹起来,并在原始查询完成后执行订阅。为确保订阅不会多次创建,您可以将它添加到组件状态中。有关更多详细信息,请参阅示例。
[document]:这是一个必要属性,它接受一个由gql模板字符串标签创建的GraphQL订阅。它应包含一个单独的GraphQL订阅操作,其中将返回数据。[variables]:您可以提供的可选变量,它们将与document选项一起使用。[updateQuery]:一个可选函数,每次服务器发送更新时都会运行。这个函数修改了HOC查询的结果。第一个参数,previousResult,将会是您在graphql()函数中定义的查询返回的前一个数据。第二个参数是一个对象,包含两个属性。subscriptionData是订阅的结果。variables是与订阅查询一起使用的变量对象。使用这些参数,您应该返回一个新的数据对象,其结构与您在graphql()函数中定义的GraphQL查询相同。这类似于fetchMore回调。[onError]:一个可选的错误回调。
为了用订阅的结果更新查询的store,您必须在subscribeToMore中的updateQuery选项或您的graphql()函数中的reducer选项中指定。
示例
class SubscriptionComponent extends Component {state = {subscriptionParam: null,unsubscribe: null,};static getDerivedStateFromProps(nextProps, prevState) {if (!nextProps.data.loading) {// Check for existing subscriptionif (prevState.unsubscribe) {// Only unsubscribe/update state if subscription variable has changedif (prevState.subscriptionParam === nextProps.subscriptionParam) {return null;}prevState.unsubscribe();}return {// Subscribeunsubscribe: nextProps.data.subscribeToMore({document: gql`subscription MySubscription {...}`,variables: {param: nextProps.subscriptionParam,},updateQuery: (previousResult, { subscriptionData, variables }) => {// Perform updates on previousResult with subscriptionDatareturn updatedResult;},}),// Store subscriptionParam in state for next updatesubscriptionParam: nextProps.subscriptionParam,};}return null;}render() {...}}
data.startPolling(interval)
此函数将设置一个间隔,并且每次这个间隔过去时都会发送一个fetch请求。该函数只接受一个整型参数,这允许您配置您希望查询以毫秒为单位的频率执行。换句话说,interval参数表示轮询之间的毫秒数。
轮询是保持UI中数据新鲜的好方法。通过每5000毫秒(或例如5秒)重新请求数据,您可以有效地模拟实时数据,而不需要构建实时后端。
如果您在查询正在轮询时调用data.startPolling,则当前轮询进程将被取消,并将使用您指定的间隔启动一个新的进程。
您还可以使用options.pollInterval在组件挂载后立即开始轮询。如果您不需要任意开始和停止轮询,建议使用options.pollInterval。
如果将您的interval设置为0,则表示不轮询,而是每个JavaScript事件循环迭代执行一次请求。
示例
class MyComponent extends Component {componentDidMount() {// In this specific case you may want to use `options.pollInterval` instead.this.props.data.startPolling(1000);}render() {// ...}}export default graphql(gql`query MyComponentQuery { ... }`)(MyComponent);
data.stopPolling()
通过调用此函数,您将停止任何当前轮询进程。您的查询不会再次开始轮询,直到您调用data.startPolling。
示例
class MyComponent extends Component {render() {return (<div><buttononClick={() => {this.props.data.startPolling(1000);}}>Start Polling</button><buttononClick={() => {this.props.data.stopPolling();}}>Stop Polling</button></div>);}}export default graphql(gql`query MyComponentQuery { ... }`)(MyComponent);
data.updateQuery(updaterFn)
这个函数允许您在突变、订阅或fetch的上下文之外更新查询的数据。此函数只接受一个参数,即另一个函数。该参数函数具有以下签名:
(previousResult, { variables }) => nextResult
第一个参数将是存储中当前存在的查询数据,并期望您返回一个新的数据对象,具有相同的形状。那个新的数据对象将被写入存储,并且跟踪该数据的任何组件都将被反应性地更新。
第二个 参数 是一个具有单个属性的 对象,variables. variables 属性允许您看到在从存储中读取 previousResult 时使用了哪些 变量。
此方法将在 不会 服务器上更新任何内容。它只会更新您客户端缓存中的数据;如果您重新加载 JavaScript 环境,则更新将消失。
示例
data.updateQuery(previousResult => ({...previousResult,count: previousResult.count + 1,}));
config.options
一个对象或函数,它返回一个用于配置如何获取和更新 查询 的选项的对象。
如果 config.options 是一个函数,则它将以组件的 props 作为其第一个 参数。
在此对象中可用的选项取决于您作为 graphql() 的第一个 参数传递的操作 类型。下面的参考将记录您的操作是一个 查询 时可用的选项。要查看对不同操作可用的其他选项,请参阅 config.options 的通用文档。
示例
export default graphql(gql`query MyQuery { ... }`, {options: {// Options go here.},})(MyComponent);
export default graphql(gql`query MyQuery { ... }`, {options: props => ({// Options are computed from `props` here.}),})(MyComponent);
options.variables
在执行 查询 操作时将使用的 变量。这些变量应与您的查询定义接受的变量相对应。如果您将 config.options 定义为一个函数,则可以从中计算您的 变量。
示例
export default graphql(gql`query MyQuery ($width: Int!, $height: Int!) {...}`,{options: props => ({variables: {width: props.size,height: props.size,},}),},)(MyComponent);
options.fetchPolicy
获取策略是一个选项,允许您指定您希望组件如何与 Apollo Client 缓存交互。默认情况下,组件将尝试从缓存中读取;如果您的查询的完整数据在缓存中,则 Apollo 将简单地将数据从缓存返回。如果查询的完整数据不在缓存中,Apollo 将使用您的网络接口执行您的请求数据。
有关支持的获取策略列表,请参阅 设置获取策略。
示例
export default graphql(gql`query MyQuery { ... }`, {options: { fetchPolicy: 'cache-and-network' },})(MyComponent);
options.errorPolicy
错误策略是一个选项,允许您指定您希望组件如何处理从 GraphQL 获取数据时可能发生的错误。在您的请求期间可能会发生两种类型的错误;客户端或服务器上的运行时错误,导致没有数据,或者可能随实际数据一起发送的一些 GraphQL 错误。为了控制您的 UI 与这些错误交互的方式,您可以使用错误策略告诉 Apollo 您何时需要知道 GraphQL 错误!
有效的 errorPolicy 值是:
none:这是默认值,我们在这里将GraphQL错误视为运行时错误。Apollo将丢弃与请求一起返回的数据,并使用具有错误 prop 的组件进行渲染。ignore:与none类似,这也会使 Apollo 忽略来自服务器的任何数据,但除了将加载状态设置回 false,它也不会更新您的界面。all选择“全部”意味着您想要在任何GraphQL错误发生时都收到通知。它将使用请求中的任何数据来渲染您的组件以及相关的错误信息。这对于服务器端渲染非常有帮助,这样您的UI始终显示一些内容。
示例
export default graphql(gql`query MyQuery { ... }`, {options: { errorPolicy: 'all' },})(MyComponent);
options.pollInterval
这表示您想要开始轮询的毫秒间隔。每当这个毫秒数过去后,您的查询将通过网络接口执行,另一个执行将使用配置的毫秒数来安排。
此选项将在组件挂载后立即开始轮询您的查询。如果您想动态地开始和停止轮询,则可以使用data.startPolling和data.stopPolling。
如果您将options.pollInterval设置为0,则意味着不会轮询,而是在每个JavaScript事件循环迭代时执行请求。
示例
export default graphql(gql`query MyQuery { ... }`, {options: { pollInterval: 5000 },})(MyComponent);
options.notifyOnNetworkStatusChange
是否应通过网络状态或网络错误更新触发组件的重渲染。
默认值是false。
示例
export default graphql(gql`query MyQuery { ... }`, {options: { notifyOnNetworkStatusChange: true },})(MyComponent);
options.context
由于Apollo Client中的Apollo Link具有灵活性和强大的功能,您可能希望将操作中的信息直接发送到您的网络链中的链!这可以用来设置HTTP请求的headers、控制向何处发送查询的端点,以及许多其他功能,这取决于您的应用程序使用的链接。context对象下的所有内容都会直接传递到您的网络链。有关使用上下文的信息,请参阅HttpLink上下文文档
partialRefetch
如果设置为true,当查询结果标记为部分时,并且由QueryManager重置为空对象(由于缓存未命中)时,将执行查询refetch。
出于向后兼容性的原因,默认值为false,但对于大多数用例应更改为true。
示例
export default graphql(gql`query MyQuery { ... }`, {options: { partialRefetch: true },})(MyComponent);
mutations的graphql()选项
props.mutate
当您将mutation传递到graphql()时创建的函数式组件将为您提供名为mutate的单个prop。与将query传递到graphql()时获得的data属性不同,mutate是一个函数。
该mutate函数实际会使用网络接口执行您的mutation,从而修改您的数据。该mutate函数还会根据您定义的方式更新缓存。
要了解更多关于突变如何工作的信息,请务必查看突变使用文档。
函数mutate接受与函数config.options用于突变相同的选项,所以请务必阅读该文档,了解可以传递给mutate函数的内容。
函数mutate接受相同选项的原因是,它将默认使用config.options中的选项。当您将对象传递给mutate函数时,您只是在config.options中覆盖了现有内容。
示例
function MyComponent({ mutate }) {return (<buttononClick={() => {mutate({variables: { foo: 42 },});}}>Mutate</button>);}export default graphql(gql`mutation MyMutation { ... }`)(MyComponent);
config.options
一个对象或函数,它返回一个用于配置如何获取和更新 查询 的选项的对象。
如果 config.options 是一个函数,则它将以组件的 props 作为其第一个 参数。
此对象中可用的选项取决于您传递给graphql()的第一个参数的操作类型。下面的参考资料将记录在您的操作为突变时,哪些选项是可用的。要查看针对不同操作的其他选项,请参阅config.options的通用文档。
此类选项对象中接受的属性也可能被props.mutate函数接受。传递给mutate函数的任何选项都将优先于config对象中定义的选项。
示例
export default graphql(gql`mutation MyMutation { ... }`, {options: {// Options go here.},})(MyComponent);
export default graphql(gql`mutation MyMutation { ... }`, {options: props => ({// Options are computed from `props` here.}),})(MyComponent);
function MyComponent({ mutate }) {return (<buttononClick={() => {mutate({// Options are component from `props` and component state here.});}}>Mutate</button>);}export default graphql(gql`mutation MyMutation { ... }`)(MyComponent);
options.variables
将用于执行突变操作变量的变量。这些变量应与您的突变定义接受的变量对应。如果您将config.options定义为一个函数,或将变量传递给props.mutate函数,则可以从属性和组件状态中计算变量。
示例
export default graphql(gql`mutation MyMutation ($foo: String!, $bar: String!) {...}`,{options: props => ({variables: {foo: props.foo,bar: props.bar,},}),},)(MyComponent);
选项.optimisticResponse
在在您询问服务器之前,通常在更改数据时,可以相当容易地预测突变的响应。乐观响应选项允许您在突变实际上完成之前,在您的UI中模拟突变的结果,从而让您的突变感觉更快。
要了解更多关于乐观数据的好处以及如何使用它们,请务必阅读关于乐观UI的教程。
此乐观响应将与options.update和options.updateQueries一起使用,以应用到您的缓存中的更新,该更新将在应用真实响应的更新之前被回滚。
示例
function MyComponent({ newText, mutate }) {return (<buttononClick={() => {mutate({variables: {text: newText,},// The optimistic response has all of the fields that are included in// the GraphQL mutation document below.optimisticResponse: {createTodo: {id: -1, // A temporary id. The server decides the real id.text: newText,completed: false,},},});}}>Add Todo</button>);}export default graphql(gql`mutation CreateTodo ($text: String!) {createTodo(text: $text) {idtextcompleted}}`)(MyComponent);
选项.update
此选项允许您根据您的 mutation 结果来更新您的商店。默认情况下,Apollo 客户端会更新您商店中所有重叠的节点。任何定义为 fields 的与 dataIdFromObject 返回的相同 id share object 将会与 dataIdFromObject 的新 fields 更新。但有时候这并不足够。有时候您可能希望按缓存中的当前数据依赖方式更新您的缓存。为此更新,您可以使用 options.update 函数。
options.update 接收两个参数。第一个是一个 DataProxy 对象的实例,该对象具有一些允许您与商店中的数据进行交互的方法。第二个来自您的 mutation 的响应——或者是乐观响应,或者是您的服务器返回的实际响应(有关详细信息,请参阅 mutation 渲染属性 部分的说明)。
为了更改您商店中的数据,请调用您的 DataProxy 实例上的方法,例如 writeQuery 和 writeFragment。这将更新您的缓存,并触发任何查询受影响数据的 GraphQL 组件的重新渲染。
要读取您正在更改的商店中的数据,请确保使用您的 DataProxy 上的方法,如 readQuery 和 readFragment。
有关使用 options.update 函数在 mutation 之后更新缓存的信息,请务必阅读有关本主题的 Apollo 客户端技术文档。
示例
const query = gql`query GetAllTodos { todos { ... } }`;export default graphql(gql`mutation CreateTodo ($text: String!) {createTodo(text: $text) { ... }}`,{options: {update: (proxy, { data: { createTodo } }) => {const data = proxy.readQuery({ query });data.todos.push(createTodo);proxy.writeQuery({ query, data });},},},)(MyComponent);
options.refetchQueries
有时当您执行 mutation 时,您也想要更新查询中的数据,以便用户可以看到最新的用户界面。更新缓存中的数据还有更精细的方法,包括 options.updateQueries 和 options.update。然而,您可以使用 options.refetchQueries 更可靠地更新缓存中的数据,尽管这会牺牲效率。
options.refetchQueries 将执行一个或多个查询,使用您的网络接口,然后将这些查询的规范结果集成到缓存中。这使得您可以潜在地重新获取之前获取的查询,或获取全新的查询。
options.refetchQueries 是一个字符串数组或对象数组,或者是一个函数,该函数接收 mutation 的结果并返回一个字符串或对象数组。
如果 options.refetchQueries 是一个字符串数组,则 Apollo 客户端会查找与提供的字符串具有相同名称的任何查询,并使用当前的 variables 重新查询这些查询。例如,如果您有一个名为 Comments 的 GraphQL 查询组件(该查询可能如下所示:query Comments { ... }),并且您将包含 Comments 的字符串数组传递到 options.refetchQueries,则 Comments 查询将被重新执行,并且在解析后最新的数据将反映在您的界面中。
如果 options.refetchQueries 是一个对象数组,则这些对象必须有两个属性:
query: 查询 是一个必需属性,它接受使用 GraphQL 查询模板字符串创建的 GraphQL 查询。它应包含一个将在突变完成时执行的 GraphQL 查询操作。{variables}: 是一个可选的对象变量,如果query接受一些变量,则必须使用它。
如果指定了这种形状的对象数组,则 Apollo 客户端将使用这些变量重新查询这些查询。
示例
export default graphql(gql`mutation MyMutation { ... }`, {options: {refetchQueries: ['CommentList', 'PostList'],},})(MyComponent);
import { COMMENT_LIST_QUERY } from '../components/CommentList';export default graphql(gql`mutation MyMutation { ... }`, {options: props => ({refetchQueries: [{query: COMMENT_LIST_QUERY,},{query: gql`query GetPostById ($id: ID!) {post(id: $id) {commentCount}}`,variables: {id: props.postID,},},],}),})(MyComponent);
export default graphql(gql`mutation MyMutation { ... }`, {options: {refetchQueries: mutationResult => ['CommentList', 'PostList'],},})(MyComponent);
请注意,重新查询的查询是异步处理的,默认情况下不一定在突变完成之前完成。如果您想在突变被视为完成(或已解决)之前确保重新查询的查询已完成,请将 options.awaitRefetchQueries 设置为 true。
options.awaitRefetchQueries
使用 options.refetchQueries重新查询的查询是异步处理的,这意味着默认情况下它们不一定在突变完成之前完成。将 options.awaitRefetchQueries 设置为 true将确保在突变被视为完成(或已解决)之前完成重新查询的查询。默认情况下, options.awaitRefetchQueries 为 false。
options.updateQueries
注意:我们建议使用 options.update 而不是 updateQueries。将在 Apollo Client 的下一个版本中删除 updateQueries。
此选项允许您根据突变的结果更新您的存储。默认情况下,Apollo 客户端将更新存储中所有重叠的节点。任何与您定义的 dataIdFromObject 返回的 id 相同的东西都将使用突变结果的新字段进行更新。然而,有时这并不足够。有时您可能希望以依赖于您存储中的当前数据的方式更新您的缓存。对于这些更新,您可以使用 options.updateQueries 函数。
options.updateQueries接受一个对象,其中查询名称是键,reducer函数是值。如果您熟悉Redux,那么定义您的options.updateQueriesreduce函数与定义Redux reduce函数非常相似。对象看起来可能如下所示:
{Comments: (previousData, { mutationResult, queryVariables }) => nextData,}
请确保您的options.updateQueries对象的键对应于您在应用程序其他地方实际执行的查询。查询名称将是您指定查询操作类型后放入的名称。例如在下面的查询中:
query Comments {entry(id: 5) {comments {...}}}
查询名称将是Comments。如果您在应用程序的任何地方都没有用名称为Comments执行过GraphQL查询,那么reduce函数将永远不会由Apollo运行,并且options.updateQueries中的键/值对将被忽略。
您提供的对象值作为您对象的值的函数的第一个参数将是您的查询的旧数据。所以如果您的键是Comments,则第一个参数将是您的Comments查询返回的最后数据对象,或者是由使用此查询的任何组件渲染的当前对象。
您的函数值作为第二个参数将是一个具有三个属性的对象:
mutationResult:代表您的mutation在击中服务器后的结果。如果您提供了options.optimisticResponse,则mutationResult可能就是该对象。queryVariables:是执行查询时使用的最后一组变量。这很有用,因为当您指定查询名称时,它只会更新当前变量集的存储中的数据。queryName:这是您要更新的查询的名称。它与您提供给options.updateQueries的键相同。
您options.updateQueries函数的返回值必须与您的第一个previousData参数具有相同的形式。但是,您不能对previousData对象进行修改。相反,您必须使用更改创建一个新对象。就像在Redux reduce中一样。
示例
export default graphql(gql`mutation SubmitComment ($text: String!) {submitComment(text: $text) { ... }}`,{options: {updateQueries: {Comments: (previousData, { mutationResult }) => {const newComment = mutationResult.data.submitComment;// Note how we return a new copy of `previousData` instead of mutating// it. This is just like a Redux reducer!return {...previousData,entry: {...previousData.entry,comments: [newComment, ...previousData.entry.comments],},};},},},},)(MyComponent);
withApollo(component)
import { withApollo } from '@apollo/client/react/hoc';
一个增强器,提供对您ApolloClient实例的直接影响。如果您想在Apollo中进行自定义逻辑,例如执行一次性查询,这很有用。通过使用要增强的组件调用此函数,withApollo()创建一个新的组件,作为client属性将传递一个ApolloClient实例。
大多数情况下,你应使用 graphql() 代替 withApollo()。 graphql() 提供了一些有用的功能来帮助你处理 GraphQL 数据。除非你希望使用没有这些功能的 withApollo() 来获取 GraphQL 客户端,否则你应当使用它。
这只能在你的组件树中有一个 <ApolloProvider/> 组件且该组件实际上提供了客户端的情况下提供对客户端的访问。
示例
function MyComponent({ client }) {console.log(client);}export default withApollo(MyComponent);