Как я могу сделать Mutliple GraphQl запросов с тем же запросом, используя реагировать-Apollo? - PullRequest
1 голос
/ 27 января 2020

У меня есть конечная точка graphql: QueryDataForOptions

Я хочу вызвать ее несколько раз, исходя из значения options компонента. Вариантов может быть любое количество.

Я бы хотел сделать что-то вроде этого псевдокода, но правила хуков этого не позволяют:

const MyComponent = (options) => {
  options.forEach(option => {
    const {data, loading, error} = useQuery(QueryDataForOptions, {variables: {option}})
  })

}

I также рассматривал этот псевдокод, но я не уверен, как справиться с перезаписью data:

const MyComponent = (options) => {
  const [getOptions, {data, loading, error}] = useLazyQuery(QueryDataForOptions)
  options.forEach(option => {
    getOptions({variables: {option}})
  })
}

Я знаю, что правильным решением является изменение конечной точки graphql, но я хочу сделать это изменение на стороне клиента.

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

Ответы [ 2 ]

1 голос
/ 28 января 2020

Apollo не предоставляет хук для одновременного запроса нескольких операций. Однако GraphQL поддерживает запрос нескольких root полей на операцию. Этот факт в сочетании с возможностью создания псевдонимов полей означает, что вы можете получить все необходимые данные в одном запросе.

При составлении запросов обычно следует избегать интерполяции строк, но в этом случае нам потребуется использовать его.

const MyComponent = (options) => {
  const query = gql`
  query SomeNameForYourOperation (
    ${options.map((option, index) => `$opt${index}: SomeInputType!`).join('\n')}
  ){
    ${options.map((option, index) => `
      alias${index}: someRootField(someArgument: $opt${index}) {
        ...SomeTypeFragment
      }
    `).join('')}
  }

  fragment SomeTypeFragment on SomeType {
    someField
    someOtherField
  }
  `

  const variables = options.reduce((memo, option, index) => {
    return { ...memo, [`opt${index}`]: option }
  }, {})

  const { data, loading, error } = useQuery(query, { variables })

  if (data) {
    // data.alias0
    // data.alias1
    // etc.
    // You can also iterate through options again here and access the
    // appropriate alias by the index
  }
}

Это выглядит немного сложно, но на самом деле это довольно просто. Мы генерируем определения переменных путем итерации по options (в итоге мы получаем переменные типа $opt0, $opt1 и т. Д. c.). Затем мы снова перебираем опции, чтобы сгенерировать набор выбора для root. Для каждого параметра мы добавляем одно и то же поле в наш запрос, но используем его псевдоним (например, alias0, alias1 и т. Д. c.), А затем передаем другую переменную в аргумент для поля. Наконец, мы используем фрагмент, чтобы сохранить размер результирующего запроса управляемым.

Мы также должны передать объект variables в useQuery, который соответствует сгенерированным нами определениям переменных, поэтому мы reduce options массив в объект с соответствующим именем свойства.

Конечно, вам нужно изменить приведенный выше пример, чтобы включить типы, поля и аргументы, указанные c в ваш запрос. Конечным результатом является то, что у вас есть один набор переменных data, loading и error. После загрузки запроса вы можете получить доступ к каждому результату под соответствующим псевдонимом (alias0, et c.).

0 голосов
/ 28 января 2020

Вместо того чтобы делать запрос для каждого option, вы должны запрашивать их все сразу. Таким образом, ваш запрос будет принимать массив, который, как я предполагаю, будет идентификатором для каждой опции, и возвращать обратно массив, по одному для каждой опции. Если у вас есть 50 вариантов, один запрос будет поразительно быстрее и лучше, чем попытка запустить один запрос для каждого параметра.

Другой, менее предпочтительный вариант - создать компонент для каждого параметра, который запускает свой собственный запрос. , Так что-то типа

const MyComponent = (options) => (
  options.forEach(option => <OptionComponent option={option} />)
)

const OptionComponent = ({ option }) => {
  const [getOptions, {data, loading, error}] = useLazyQuery(QueryDataForOptions);

  if (loading) return 'Loading...';

  return (
    // whatever you want for each option
  );
}
...