Как передать переменные в запрос GraphQL?

Предположим, у меня есть следующий запрос GraphQL в React-Apollo

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, как я могу сообщить об этом родительскому компоненту?

3 ответа

Решение

Пока я знаю два возможных подхода к этому.

Первый уже указан в вопросе. Переменные одновременно являются опорами ProfileWithData, Таким образом, вам нужно найти способ изменить реквизит и изменить компонент. Обычно это достигается с помощью родительского компонента. Поэтому обычно вы не меняете переменные внутри ProfileWithData, Этот компонент должен использоваться только для целей отображения. Однако это не говорит о том, что это невозможно сделать. Вы можете передать методы вашего родительского компонента ребенку, чтобы манипулировать состоянием родителя. Это переопределяет оба компонента и отображает ProfileWithData с новыми реквизитами / переменными.

Второй подход заключается в запросе изнутри ProfileWithData составная часть. Затем вы можете манипулировать переменными изнутри компонента с помощью состояния. Способ сделать это можно найти здесь

Вы можете сделать это, передав ссылку на клиент Apollo, используя withApollo компонент высшего порядка, как описано здесь: http://dev.apollodata.com/react/higher-order-components.html

Затем вы можете позвонить client.query на переданный в объект, вот так:

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

      render() { ... }
    }

    withApollo(MyComponent);

До Apollo Client 2.1

До версии Apollo Client 2.1, когда вам приходилось использовать компоненты высшего порядка (HOC), было два решения, которые Хенк правильно указал в другом ответе. Я постараюсь кратко их обобщить:

  • Поскольку HOC имеет доступ только к подпоркам, вам необходимо ввести изменяющуюся переменную в родительский компонент. Например, родительский компонент может иметь локальное управление состоянием для изменяющейся переменной с помощью React setState() метод. Как только переменная изменится в локальном состоянии, она может быть передана другому компоненту, который улучшен HOC. HOC имеет доступ к реквизиту и может выполнить запрос с измененной переменной. Подсказка: если вы не хотите вводить другой компонент между ними для изменения локального состояния, поменяйте withState HOC может быть отличным выбором.

  • Второй способ, но, возможно, менее элегантный, поскольку он переводит ваш код из декларативного в императивный, заключается в использовании 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, вы можете передать изменяющуюся опору в качестве переменной компоненту 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>
);

Примечание. Фрагменты кода взяты из публикации блога Apollo Client 2.1.

Ваш ProfileWithData Компонент хорошо выполняет рендеринг аватара определенного пользователя. Этот компонент не отвечает за управление изменениями отображаемого в данный момент компонента аватара.

Один из способов - добавить новую опору. avatarId который передается от родительского компонента. Тогда вам нужно будет написать это:

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

Если вы знакомы с react-routerДругой подход заключается в использовании параметров маршрута для определения идентификатора аватара. Вам нужно будет настроить вызов graphql как это:

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

Чтобы узнать больше об использовании переменных запроса, подобных этой, вы можете проверить " Реакцию по изучению Аполлона".

Другие вопросы по тегам