React Apollo - Сделать несколько запросов

У меня есть файл запросов, который выглядит так:

import {gql} from 'react-apollo';

const queries = {
  getApps: gql'
    {
      apps {
        id
        name
      }
    }
  ',
  getSubjects: gql'
    {
      subjects {
        id
        name
      }
    }
  '
};

export default queries;

Затем я импортирую этот файл в компонент React:

import React, {Component} from 'react'
import queries from './queries'

class Test extends Component {
...
}

export default graphql(queries.getSubjects)(graphql(queries.getApps)(Test));

Это будет получать данные только для одного из запросов (getApps), а не для обоих. Если я делаю одно за раз, чтобы оно выглядело так:

export default graphql(queries.getSubjects)(Test);

то он работает, но у меня нет другого запроса. Да, я тестировал и отдельно, и они работают. Как получить его, чтобы оба запроса отображались в моем файле props.data?

Ответ 1

Мой предпочтительный способ - использовать функциональность compose клиента apollo (документ).

РЕДАКТИРОВАТЬ: Если у вас есть более одного запроса, вы должны назвать их.

Так что в вашем случае это может выглядеть так:

import React, {Component} from 'react'
import queries from './queries'
import { graphql, compose } from 'react-apollo';

class Test extends Component {
...

  render() {
    ...
    
    console.log(this.props.subjectsQuery, this.props.appsQuery); // should show both 
    
    ...
  }
}

export default compose(
   graphql(queries.getSubjects, {
      name: "subjectsQuery"
   }),
   graphql(queries.getApps, {
      name: "appsQuery"
   }),
)(Test);

Ответ 2

ИМХО, одно из самых аккуратных решений описано в реализации Apollo Client React.
Основная идея заключается в том, чтобы обернуть ваши запросы во вложенные компоненты запроса. Использование функций замыкания в качестве дочерних компонентов делает удобным делегирование результатов одного запроса в другой запрос и так далее.

 const QueryOne = gql'
  query One {
    one
  }
';

const QueryTwo = gql'
  query Two {
    two
  }
';

const NumbersWithData = () => (
  <Query query={QueryOne}>
    {({ loading: loadingOne, data: { one } }) => (
      <Query query={QueryTwo}>
        {({ loading: loadingTwo, data: { two }}) => {
          if (loadingOne || loadingTwo) return <span>loading...</span>
          return <h3>{one} is less than {two}</h3>
        }}
      </Query>
    )}
  </Query>
);

Ответ 3

Если вы не хотите повторно использовать любой из этих запросов независимо, почему бы не сделать один запрос, объединив оба запроса в одном, то есть:

const combinedQueries = gql'
{
  apps {
    id
    name
  }
  subjects {
    id
    name
  }
}
'

и затем вы можете использовать его в своем компоненте

import React, {Component} from 'react'
import combinedQueries from './combinedQueries'

class Test extends Component {
   ...
   render() {
     ...
     if(!this.props.combinedQueries.loading) {
       console.log(this.props.combinedQueries.apps);
       console.log(this.props.combinedQueries.subjects);
     }
     ...
   }
}

export default graphql(combinedQueries, {name: 'combinedQueries'})(Test);

Ответ 4

Для Apollo 2.x: вы можете использовать react-adopt чтобы объединить запросы и мутации в один уровень. (Эта библиотека будет составлять любые компоненты с реквизитами рендеринга, например, React Context API.)

https://github.com/pedronauck/react-adopt

Ответ 5

Я использую ответную реакцию, чтобы сделать это. Это действительно просто и держать наш код в чистоте.

Простой пример:

import { adopt } from 'react-adopt';

...
render() {
  const Composed = adopt({
    first: ({ render }) => <Query query={FIRST_QUERY}>{ render }</Query>,
    second: ({ render }) => <Query query={SECOND_QUERY}>{ render }</Query>
  });

  return (
    <Composed>
      ({ first, second }) => {
        console.log('first', first)
        console.log('second', second)

        // validations (loading, error)

        return (
          <div>Your JSX</div>
        )
      }
    </Composed>
  )
}
...

Есть много примеров использования

const Composed = adopt({
  first: <Query query={FIRST_QUERY} />,
  second: <Query query={SECOND_QUERY} />
});

Будьте осторожны с компонентом <Query>, он нуждается в дочерних элементах, в противном случае он будет иметь следующую ошибку:

Warning: Failed prop type: The prop children is marked as required in Query, but its value is undefined.

Чтобы избежать предыдущего предупреждения, я нашел возможное решение:

first: ({ render }) => <Query query={FIRST_QUERY}>{ render }</Query>

Надеюсь, это поможет вам!

Ответ 6

Другой способ - использовать опцию props.

export default compose(
  graphql(QUERY_2, {
    props: ({ data }) => ({ ...data }),
  }),
  graphql(QUERY_1, {
    props: ({ data }) => ({ ...data, myCustomAttribute: data.foo }),
  }),
)(Component);

Я обнаружил, что этот подход немного лучше для моего случая использования.

Вот ссылка на документы: https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-config-props

Ответ 7

Запрос и мутация с использованием реагировать-apollo compose

Вещи, которые я пришел к выводу:

  1. Compose запускает запросы снизу вверх.
  2. Запросы выполняются автоматически, вам не нужно их вызывать, но вы делаете мутации.
  3. Очевидно, что команда Apollo хочет, чтобы все использовали компонент Query, а не сочиняли. Поэтому, я думаю, было бы разумно использовать их Query Component, как они предлагают, потому что они могут отказаться от создания позже.

Вот код, если вы все еще хотите использовать compose:

import {gql} from 'graphql-tag'
import {graphql, compose} from 'react-apollo'
import React, {Component} from 'react'

const appQuery = gql'
    {
      apps {
        id
        name
      }
    }
  '

const subjectMutation = gql'
    mutation someName($name: String) {
      changeSubjects(name: $name) {
        subject {
          name
        }
      }
    }
  '
};

class Test extends Component {
...

  const MutationResponse = this.props.mutate({
    variables: {
      name: "some name"
    }
  })

  const QueryResponse = this.props.data.appQuery

...
}

export default compose(
  graphql(appQuery),
  graphql(subjectMutation) 
)(Test));