13

假设我在 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 组件知道呢?

4

3 回答 3

8

在 Apollo Client 2.1 之前

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

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

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

从 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 客户端,请查看这个广泛的教程。注意:代码片段取自 Apollo Client 2.1 发布博客文章。

于 2018-04-22T06:06:19.330 回答
5

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

要了解有关此类查询变量用法的更多信息,您可以查看Learn Apollo 的 React Track

于 2017-01-03T02:10:10.030 回答
2

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

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

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

您可以通过使用 withApollo更高阶组件传递对 Apollo 客户端的引用来完成此操作,如此处所述: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);
于 2017-11-19T14:22:07.903 回答