如何将变量传递给 GraphQL 查询?

Posted

技术标签:

【中文标题】如何将变量传递给 GraphQL 查询?【英文标题】:How to pass variables to a GraphQL query? 【发布时间】:2017-05-15 14:36:28 【问题描述】:

假设我在 React-Apollo 中有以下 GraphQL 查询

const CurrentUserForLayout = gql`
  query CurrentUserForLayout($avatarID: Int!) 
    currentUser 
      avatar_url(avatarID: $avatarID)
    
  
`;

const ProfileWithData = graphql(CurrentUserForLayout, 
  options:  variables:  avatarID: 1  ,
)(Profile);

现在如果我想让我的 React 组件Profile 更改头像ID,

我该怎么做?

我是 React 和 GraphQl 的新手,我不太了解这里的联系:

graphql(CurrentUserForLayout, 
      options:  variables:  avatarID: 1  ,
    )(Profile);

我真的需要ProfileWithData 周围的另一个父组件吗? 将另一个avatarID 传递给查询?但是如果 ID 是由 Profile 组件操作的,我该如何让 Parent 组件知道呢?

【问题讨论】:

【参考方案1】:

在 Apollo Client 2.1 之前

在 Apollo Client 2.1 之前,当您必须使用 Higher-Order Components (HOC) 时,henk 在另一个答案中正确指出了两种解决方案。我试着简要总结一下:

由于 HOC 只能访问 props,因此您需要在父组件中引入更改变量。例如,父组件可以使用 React 的 setState() 方法对更改变量进行本地状态管理。一旦变量在本地状态中发生变化,它就可以传递给您的其他组件,该组件由 HOC 增强。 HOC 可以访问 props 并且可以使用更改的变量执行查询。 提示:如果您不想在两者之间引入另一个组件来更改本地状态,recompose 的withState HOC 可能是一个不错的选择。

第二种方法,但可能不太优雅,因为它将您的代码从声明式转换为命令式,它将使用withApollo() HOC,它使您可以访问 Apollo 客户端实例作为道具。在你的 React 组件中拥有这个实例,一旦你的变量发生变化,你就可以在你的组件的一个类方法(例如 onChange 处理程序)中调用 client.query( query: ..., variables: ... )

自 Apollo Client 2.1

由于Apollo Client 2.1,您可以使用新的查询(和突变)组件。虽然 HOC 仍然存在,但不再由 documentation 宣传。但是,您的组件中使用了新的 Query(和 Mutation)组件。它使用 React 的渲染道具模式。

import React from "react";
import  Query  from "react-apollo";
import gql from "graphql-tag";

const GET_TODOS = gql`
  
    todos 
      id
      type
    
  
`;

const Todos = () => (
  <Query query=GET_TODOS>
    ( loading, error, data ) => 
      if (loading) return <p>Loading...</p>;
      if (error) return <p>Error :(</p>;

      return data.todos.map(( id, type ) => (
        <p key=id>type</p>
      ));
    
  </Query>
);

通过将此控制流转移到组件内部,而不是将其仅与 HOC 放在一起,您可以将不断变化的 prop 作为变量传递给您的 Query(和 Mutation)组件。

import React from "react";
import  Mutation  from "react-apollo";
import gql from "graphql-tag";

const TOGGLE_TODO = gql`
  mutation ToggleTodo($id: Int!) 
    toggleTodo(id: $id) 
      id
      completed
    
  
`;

const Todo = ( id, text ) => (
  <Mutation mutation=TOGGLE_TODO variables= id >
    (toggleTodo,  loading, error, data ) => (
      <div>
        <p onClick=toggleTodo>
          text
        </p>
        loading && <p>Loading...</p>
        error && <p>Error :( Please try again</p>
      </div>
    )
  </Mutation>
);

如果你想学习 React 中的 Apollo Client,请查看 this extensive tutorial。注意:代码片段摘自 Apollo Client 2.1 发布博客文章。

【讨论】:

【参考方案2】:

到目前为止,我知道两种可能的方法。

第一个已在问题中说明。变量同时是ProfileWithData 的道具。因此,您需要找到一种方法来更改道具并重新渲染组件。这通常通过父组件来实现。所以通常你不会更改ProfileWithData 内部的变量。此组件应仅用于显示目的。但是,这并不是说不能做。您可以将父组件的方法传递给子组件,以操纵父组件的状态。这将重新渲染两个组件并使用新的道具/变量渲染ProfileWithData

第二种方法是从ProfileWithData组件内部进行查询。然后,您可以使用状态从组件内部操作变量。可以找到执行此操作的方法here

您可以通过使用 withApollohigher-order-component,如此处所述: http://dev.apollodata.com/react/higher-order-components.html#withApollo

然后,您可以在传入的对象上调用client.query,如下所示:

 class MyComponent extends React.Component 
      runQuery() 
        this.props.client.query(
          query: gql`...`,
          variables:  ... ,
        );
      

      render()  ... 
    

    withApollo(MyComponent);

【讨论】:

【参考方案3】:

您的ProfileWithData 组件在渲染某个用户的头像方面做得很好。管理当前显示的头像组件的变化不是该组件的职责。

一种方法是添加一个从父组件传递下来的新道具avatarId。然后你需要这样写:

graphql(CurrentUserForLayout, 
  options: (ownProps) => (
    variables: 
      id: ownProps.avatarId
    
  )
)(Profile);

如果您熟悉react-router,另一种方法是使用路由参数来确定头像ID。您需要像这样调整graphql 的调用:

graphql(CurrentUserForLayout, 
  options: (ownProps) => (
    variables: 
      id: ownProps.params.avatarId
    
  )
)(Profile);

要详细了解此类查询变量的用法,您可以查看React Track of Learn Apollo。

【讨论】:

使用上述答案中给出的查询组件或您提到的方法哪个更好?我对 graphql 很陌生。

以上是关于如何将变量传递给 GraphQL 查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 AWS AppSync 客户端将保存字符串的变量传递给 GraphQL 查询?

ReactJS/Javascript/Graphql/React-apollo:传递查询变量

如何将变量添加到 GraphQL 文件查询

将变量从输入传递到 GraphQL 搜索调用

将变量传递给外部解析引用

如何将状态值传递给 Graphql Query