【问题标题】:React Apollo - 进行多个查询
【发布时间】:2017-09-08 21:26:38
【问题描述】:

我有一个如下所示的查询文件:

import {gql} from 'react-apollo';

const queries = {
  getApps: gql`
    {
      apps {
        id
        name
      }
    }
  `,
  getSubjects: gql`
    {
      subjects {
        id
        name
      }
    }
  `
};

export default queries;

然后我将此文件导入我的 React 组件:

import React, {Component} from 'react'
import queries from './queries'

class Test extends Component {
...
}

export default graphql(queries.getSubjects)(graphql(queries.getApps)(Test));

这只会获取其中一个查询 (getApps) 的数据,而不是两者。如果我一次做一个,它看起来像这样:

export default graphql(queries.getSubjects)(Test);

然后它可以工作,但我没有其他查询。是的,我已经分别测试了它们并且它们有效。如何获取它以便两个查询都显示在我的 props.data 中?

【问题讨论】:

    标签: javascript reactjs apollo react-apollo


    【解决方案1】:

    Apollo 客户端使用Query Hooks 的出现;改变了一切。如果您在 2020 年或以后阅读本文;我很确定您可能正在使用 Apollo 客户端 useQuery 钩子。您可以根据需要多次调用 useQuery Hook 来执行这两个查询。您可以在其官方文档https://www.apollographql.com/docs/react/data/queries/ 中了解有关 useQuery 挂钩的更多信息,我发现它在我最近的项目中非常有用。例如

    const queries = {
      getApps: gql`
        {
          apps {
            id
            name
          }
        }
      `,
    
      getSubjects: gql`
        {
          subjects {
            id
            name
          }
        }
      `
    };
    
    const { loading, error, data } = useQuery(queries);
    
    const { loading:getSubjectsLoading, error:getSubjectsError, data:getSubjects } = useQuery(getSubjects);
    
    if (loading || getSubjectsLoading) return "Loading...";
    if (error || getSubjectsError ) return <p>Error :(</p>;
    
    
    console.log(data);
    console.log(getSubjects);
    

    【讨论】:

    • Hey Emeka - 据我所知,这仍然会对 graphql 端点进行多次网络 POST 调用。你的经历也是这样吗?
    • 是的;但这就是问题所在。他想进行多个查询。这将对 graphql 服务器进行多次网络调用。
    • 好的,是的,出于某种原因,我虽然 OP 正在寻找一种方法,只使用一个调用。 (这就是我正在寻找的)。我想唯一的方法是建立一个全新的查询。谢谢。
    【解决方案2】:

    由于 compose 已从 apollo 中删除,因此有一个替代库,称为 lodash。 {flowRight} 方法的作用与 compose 相同。 只需按照以下步骤操作:-

    1. npm i -s lodash

    2. import {flowRight} from 'lodash'

    3. 将 compose 的用法与 flowRight 交换,所有其他代码都一样。

    【讨论】:

      【解决方案3】:
        const { loading: cat_loading, cat_error, data: cat_data } = useQuery(categoriesAllQuery)
        const { loading: prod_loading, prod_error, data: prod_data } = useQuery(productsAllQuery)
      
        if (cat_loading || prod_loading) return <p>Loading ... </p>
        const { categoriesAll } = cat_data
        const { productsAll } = prod_data
      

      【讨论】:

        【解决方案4】:

        根据此Link,要使用compose(),您需要按照以下步骤操作:

        1- 使用npm i recompose安装“recompose”包

        2- 使用import { compose } from "recompose";导入包

        3- 以如下形式使用它:

        export default compose(
          graphql(Query1, { alias: "Query1" }),
          graphql(Query2, { alias: "Query2" })
        )(Test);
        

        文档:https://www.apollographql.com/docs/react/api/react-apollo/

        【讨论】:

          【解决方案5】:

          我的首选方式是使用 apollo 客户端 (docu) 的 compose 功能。

          编辑: 如果您有多个查询,则应为它们命名。

          所以在你的情况下,它可能看起来像这样:

          import React, {Component} from 'react'
          import queries from './queries'
          import { graphql, compose } from 'react-apollo';
          
          class Test extends Component {
          ...
          
            render() {
              ...
              
              console.log(this.props.subjectsQuery, this.props.appsQuery); // should show both 
              
              ...
            }
          }
          
          export default compose(
             graphql(queries.getSubjects, {
                name: "subjectsQuery"
             }),
             graphql(queries.getApps, {
                name: "appsQuery"
             }),
          )(Test);

          【讨论】:

          • 我确实这样做了,但无济于事:(
          • 奇怪,你有没有在渲染函数中尝试console.log(this.props)
          • 是的,我试过了,只看到了我期待的属性之一
          • 我想我遇到了问题并编辑了答案。请让我知道它是否有效
          • 错误和加载道具在相应的查询中找到,例如this.props.appsQuery.error
          【解决方案6】:

          我正在使用react-adopt 来制作这个。这真的很简单,并且保持我们的代码干净。

          简单示例:

          import { adopt } from 'react-adopt';
          
          ...
          render() {
            const Composed = adopt({
              first: ({ render }) => <Query query={FIRST_QUERY}>{ render }</Query>,
              second: ({ render }) => <Query query={SECOND_QUERY}>{ render }</Query>
            });
          
            return (
              <Composed>
                ({ first, second }) => {
                  console.log('first', first)
                  console.log('second', second)
          
                  // validations (loading, error)
          
                  return (
                    <div>Your JSX</div>
                  )
                }
              </Composed>
            )
          }
          ...
          

          有很多例子使用

          const Composed = adopt({
            first: <Query query={FIRST_QUERY} />,
            second: <Query query={SECOND_QUERY} />
          });
          

          注意&lt;Query&gt;组件,它需要一个children,否则会报如下错误:

          Warning: Failed prop type: The prop children is marked as required in Query, but its value is undefined.
          

          为了避免前面的警告,我找到了一个可能的解决方案:

          first: ({ render }) => <Query query={FIRST_QUERY}>{ render }</Query>
          

          希望对你有帮助!

          【讨论】:

          • 如果您应用了 Query 组件而不是仅仅 console.log 它们 IMO 会更好理解。
          【解决方案7】:

          恕我直言,Apollo Client React implementation 中描述了最简洁的解决方案之一。
          基本思想是将您的查询包装到嵌套的查询组件中。使用闭包函数作为子组件可以方便地将一个查询的结果委托给另一个查询,依此类推。

           const QueryOne = gql`
            query One {
              one
            }
          `;
          
          const QueryTwo = gql`
            query Two {
              two
            }
          `;
          
          const NumbersWithData = () => (
            <Query query={QueryOne}>
              {({ loading: loadingOne, data: { one } }) => (
                <Query query={QueryTwo}>
                  {({ loading: loadingTwo, data: { two }}) => {
                    if (loadingOne || loadingTwo) return <span>loading...</span>
                    return <h3>{one} is less than {two}</h3>
                  }}
                </Query>
              )}
            </Query>
          );
          

          【讨论】:

          • 我没有得到反对,因为 [1] 描述了这些嵌套的 &lt;Query&gt;…&lt;/Query&gt; 结构将是使用 compose 的结果。因此,在compose 显得笨拙或者您只是不想构建另一个组件的情况下使用它可能是合理的。 [1]:apollographql.com/docs/react/…
          • 请注意,这看起来 QueryTwo 将仅在 QueryOne 返回后运行,但请注意 QueryTwo 不会等待 loadingOne 变为 false,因此它们实际上将并行运行。除非您想使用 QueryOne 结果作为 QueryTwo 的参数,在这种情况下,您可以在呈现 QueryTwo 之前等待 loadingOne
          • 我不同意这是“整洁”,它看起来像是一个正在制作的嵌套渲染道具地狱。
          • 我同意这很简洁,因为它允许您使用自己的查询构建可组合的组件。例如,您可以拥有一个处理类别分页列表的父组件。它可以不知道哪些孩子会被渲染。因此,您可以拥有一个列出作者并呈现每个作者的作者详细信息的屏幕。第一个组件查询作者和第二个作者详细信息。您可以使用相同的顶部组件来查询文章,并使用不同的组件来查询文章的详细信息。真的很整齐!但是,显然很难有一个加载状态。
          【解决方案8】:

          对于Apollo 2.x:您可以使用react-adopt 将查询和突变组合成一个级别。 (该库将使用渲染道具组合任何组件,例如 React Context API。)

          https://github.com/pedronauck/react-adopt

          【讨论】:

          • 我发现 refetch 没有使用 adpot 更新 UI:/
          • 关于refetch() 的同样问题,在重新获取@JamieHutber 时使用react-adopt 的任何解决方法?
          • 是的,如果你需要,我可以写出来。但本质上,该查询公开了一个refetch 方法,您可以保留该方法,直到您进行突变。仍然让我知道我会在这个网站上添加一个答案。
          • @JamieHutber 如果您能发帖,我将不胜感激!
          【解决方案9】:

          如果您不想单独重用这些查询中的任何一个,为什么不通过将两个查询合并为一个来发出单个请求,即:

          const combinedQueries = gql`
          {
            apps {
              id
              name
            }
            subjects {
              id
              name
            }
          }
          `
          

          然后你就可以在你的组件中使用它了

          import React, {Component} from 'react'
          import combinedQueries from './combinedQueries'
          
          class Test extends Component {
             ...
             render() {
               ...
               if(!this.props.combinedQueries.loading) {
                 console.log(this.props.combinedQueries.apps);
                 console.log(this.props.combinedQueries.subjects);
               }
               ...
             }
          }
          
          export default graphql(combinedQueries, {name: 'combinedQueries'})(Test);
          

          【讨论】:

          • 如果其中一个失败而另一个没有怎么办?我可以单独重试吗?
          【解决方案10】:

          解决此问题的另一种方法是使用props 选项。

          export default compose(
            graphql(QUERY_2, {
              props: ({ data }) => ({ ...data }),
            }),
            graphql(QUERY_1, {
              props: ({ data }) => ({ ...data, myCustomAttribute: data.foo }),
            }),
          )(Component);
          

          我发现这种方法更适合我的用例。

          这是文档的链接:https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-config-props

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-05-13
            • 2018-07-23
            • 2019-03-09
            • 2017-02-10
            • 2017-10-05
            • 2021-05-17
            • 2019-12-06
            相关资源
            最近更新 更多