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

15

假设我在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 组件篡改了,我该如何让父组件知道呢?

3个回答

8

Apollo Client 2.1之前

在Apollo Client 2.1之前,当你需要使用高阶组件(HOCs)时,有两种解决方案被正确地指出了,这些方案由henk在另一个答案中进行了概述。我会简要总结一下:

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

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

自Apollo Client 2.1以来

自从Apollo Client 2.1以来,您可以使用新的Query(和Mutation)组件。HOC仍然存在,但不再由文档广告。但是,新的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,请查看这个详细的教程。注意:代码片段取自Apollo Client 2.1发布博客文章。

5

您的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);

如果您想了解更多关于这样使用查询变量的内容,可以查看Learn Apollo的React教程


使用上面答案中提供的查询组件还是您提到的方法更好?我对GraphQL还不太熟悉。 - Rupesh

2

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

第一种方法已经在问题中说明。变量同时是ProfileWithData的props。因此,你需要找到一种改变props并重新渲染组件的方法。通常这是通过父组件实现的。因此,通常不应该改变ProfileWithData内部的变量。这个组件应该仅用于展示目的。但是,这并不意味着不可能。你可以将父组件的方法传递给子组件,以便操作父组件的状态。这将重新渲染两个组件并使用新的props/变量来渲染ProfileWithData

第二种方法是从ProfileWithData组件内部查询。然后,你可以通过state在组件内部操作变量。可以在这里找到执行此操作的方法。

You can do it by passing a reference to Apollo Client using the withApollo higher-order-component, as documented here: http://dev.apollodata.com/react/higher-order-components.html#withApollo

Then, you can call client.query on the passed in object, like so:

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

      render() { ... }
    }

    withApollo(MyComponent);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接