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

时间:2016-12-31 18:13:23

标签: reactjs react-apollo

假设我在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更改avatarID,

我该怎么做?

我是React和GraphQl的新手,我真的不明白这里的连接:

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

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

3 个答案:

答案 0 :(得分:6)

在Apollo Client 2.1之前

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

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

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

自Apollo Client 2.1

Apollo Client 2.1开始,您可以使用新的Query(和Mutation)组件。 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发布博客文章。

答案 1 :(得分:3)

您的ProfileWithData组件可以很好地呈现某个用户的头像。管理当前显示的头像组件的更改不是此组件的责任。

一种方法是添加从父组件传递下来的新prop 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

答案 2 :(得分:2)

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

问题中已经说明了第一个。变量同时是ProfileWithData的道具。所以你需要找到一种方法来改变道具并重新渲染组件。这通常通过父组件实现。所以通常你不会改变ProfileWithData里面的变量。该组件应仅用于显示目的。但是,这并不是说它无法完成。您可以将父组件的方法传递给子组件,以便操纵父组件的状态。这将重新呈现两个组件并使用新的props /变量呈现ProfileWithData

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

  

您可以使用以下命令传递对Apollo Client的引用   withApollo高阶组件,如下所示:   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);