🌸 GraphQL

useQuery, useLazyQuery (공식 문서 참고)

ji-hyun 2022. 3. 8. 04:50

useQuery

useQuery React hook 은 Apollo 애플리케이션에서 쿼리를 실행하기 위한 기본 API 입니다.

React 컴포넌트 내에서 쿼리를 실행하려면 useQuery GraphQL 쿼리 문자열을 호출하고 전달합니다.

 

 

컴포넌트가 랜더링되면 UI 를 랜더링하는데 사용할 수 있는 

useQuery 는 아폴로 클라이언트로부터 객체를 리턴한다.

loading, error, data

 

 

 

예를 들어 보겠습니다.

GET_DOGS 라는 GraphQL 쿼리를 생성합니다.

 

import { gql, useQuery } from '@apollo/client';

const GET_DOGS = gql`
  query GetDogs {
    dogs {
      id
      breed
    }
  }
`;

 

 

 

 

 

 

다음으로 Dogs 라는 구성요소를 만들고, 그 안에서 GET_DOGS 쿼리를 useQuery 훅에 전달합니다.

 

function Dogs({ onDogSelected }) {
  const { loading, error, data } = useQuery(GET_DOGS);

  if (loading) return 'Loading...';
  if (error) return `Error! ${error.message}`;

  return (
    <select name="dog" onChange={onDogSelected}>
      {data.dogs.map(dog => (
        <option key={dog.id} value={dog.breed}>
          {dog.breed}
        </option>
      ))}
    </select>
  );
}

 

쿼리가 실행되고, loading, error, data 값이 변경되면 Dogs 컴포넌트는 쿼리 상태에 따라 다양한 UI 요소를 지능적으로 랜더링할 수 있습니다.

 

loading 이 true : 쿼리가 아직 진행 중임을 나타내는 동안 컴포넌트는 Loading.. 을 표시합니다.

loading 이 false 이고 error 가 없다면 : query 는 완성된 것입니다.

컴포넌트는 서버에서 반환한 개 품종 목록으로 채워진 드롭다운 메뉴를 랜더링합니다. 

 

 

사용자가 data 가 채워진 드롭다운에서 개 품종을 선택하면 그 선택 항목은 부모 컴포넌트로 전송됩니다 . (onDogSelected 통해서)

 

 

 

다음 단계에서는 드롭다운을 GraphQL 변수를 사용하는 보다 정교한 쿼리와 연결합니다.

 

 

 

 

 

 

 

 

 

Cashing query result

 

Apollo Client 는 서버에서 쿼리 결과를 가져올 때마다 자동으로 해당 결과를 로컬로 캐시합니다.

이렇게 하면 나중에 동일한 쿼리를 매우 빠르게 실행할 수 있습니다.

 

 

이 캐싱이 작동하는지 확인하기 위해 이라는 새 컴포넌트 DogPhoto 를 빌드해 보겠습니다 .  DogPhoto 컴포넌트는 breed 라는 props 를 받아들입니다. 이 breed 는 드롭다운 메뉴의 현재 값을 반영함 

 

 

const GET_DOG_PHOTO = gql`
  query Dog($breed: String!) {
    dog(breed: $breed) {
      id
      displayImage
    }
  }
`;

function DogPhoto({ breed }) {
  const { loading, error, data } = useQuery(GET_DOG_PHOTO, {
    variables: { breed },
  });

  if (loading) return null;
  if (error) return `Error! ${error}`;

  return (
    <img src={data.dog.displayImage} style={{ height: 100, width: 100 }} />
  );
}

 

이번에는 useQuery 훅에 구성옵션(variables)을 제공합니다.

variables 옵션은 우리가 GraphQL 쿼리에 전달하려는 모든 변수를 포함하는 객체입니다.

이 경우 우리는 드롭다운에서 현재 선택된 breed 를 전달하고자 합니다.

 

 

드롭다운에서 불독을 선택하여 해당 사진이 나타나는지 확인합니다. 그런 다음 다른 품종으로 전환한 다음 다시 bulldog 으로 돌아오면 

불독 사진이 두번째로 로드되는 것을 알 수 있습니다. 이것은 작업 중인 캐시입니다.

 

다음으로 캐시된 데이터가 최신 상태인지 확인하는 몇가지 기술을 알아보겠습니다.

 

 

 

 

 

 

 

 

 

Updating cashed query results

쿼리의 캐시된 데이터가 서버의 데이터와 최신 상태인지 확인하려는 경우가 있습니다.

Apollo Client 는 이를 위해 두 가지 전략을 지원합니다. -> polling, refetching

 

 

 

 

 

Polling

Polling 은 지정된 간격으로 주기적으로 쿼리를 실행하여 서버와 거의 실시간으로 동기화합니다. 쿼리에 대한 폴링을 활성화하려면 밀리초 단위의 간격으로 pollInterval 구성 옵션을 useQuery 후크에 전달합니다.

 

function DogPhoto({ breed }) {
  const { loading, error, data } = useQuery(GET_DOG_PHOTO, {
    variables: { breed },
    pollInterval: 500,  });

  if (loading) return null;
  if (error) return `Error! ${error}`;

  return (
    <img src={data.dog.displayImage} style={{ height: 100, width: 100 }} />
  );
}

 

 

pollInterval 을 500 으로 설정하면 0.5초마다 서버에서 현재 품종의 이미지를 가져옵니다.

pollInterval 을 0 으로 설정하면 쿼리가 polling 되지 않습니다.

 

 

 

단, useQeury 에서 반환되는 startPolling 및 stopPolling 함수를 사용하여 폴링을 동적으로 시작 및 중지할 수도 있습니다.

 

 

 

 

 

 

 

 

 

refetching

refetching 을 사용하면 고정 간격을 사용하는 대신 특정 사용자 작업에 대한 응답으로 쿼리 결과를 새로 고칠 수 있습니다.

 

이번엔 버튼을 DogPhoto 컴포넌트에 추가해보겠습니다. 이 컴포넌트는 버튼을 클릭할 때마다 쿼리의 refetch 함수를 호출합니다.   

 

선택적으로 refetch 함수에 새 variables object 를 제공할 수 있습니다. 그렇지 않으면(다음 예의 경우와 같이) 쿼리는 이전 실행에서 사용한 것과 동일한 변수를 사용합니다.

 

 

function DogPhoto({ breed }) {

  const { loading, error, data, refetch } = useQuery(GET_DOG_PHOTO, {
    variables: { breed }
  });

  if (loading) return null;
  if (error) return `Error! ${error}`;

  return (
    <div>
      <img src={data.dog.displayImage} style={{ height: 100, width: 100 }} />
      <button onClick={() => refetch()}>Refetch!</button>
    </div>
  );
}

 

버튼을 클릭하고 UI가 새로운 개 사진으로 업데이트되는 것을 확인하십시오. 다시 가져오는 것은 새로운 데이터를 보장하는 훌륭한 방법이지만 로드 상태에 약간의 복잡성이 발생합니다. 다음 섹션에서는 복잡한 로딩 및 오류 상태를 처리하기 위한 전략을 다룰 것입니다.

 

 

 

 

 

 

 

refetch 에 새로운 variables 제공

 

<button onClick={() => refetch({
  breed: 'dalmatian' // Always refetches a dalmatian instead of original breed
})}>Refetch!</button>

 

원래 쿼리의 변수 중 일부 에 대해 새 값을 제공 하지만 모든 변수는 제공하지 않는 경우 refetch에서는 생략된 각 변수의 원래 값을 사용합니다.

 

 

 

 

 

 

 

 

 

Inspecting loading states (로딩 상태 검사)

 

useQuery 후크가 쿼리의 현재 loading 상태를 노출 하는 것을 이미 보았습니다 . 이것은 쿼리가 처음 로드될 때 유용하지만 refetching 이나 polling 할 때 loading 상태는 어떻게 됩니까?

 

이전 섹션의 refetch 예제로 돌아가 보겠습니다. 버튼을 클릭하면 새 데이터가 도착할 때까지 구성 요소가 다시 렌더링되지 않는 것을 볼 수 있습니다. 사진을 다시 가져오고 있음을 사용자에게 알리려면 어떻게 해야 합니까?

 

useQuery hook's result object 는 networkStatus 속성을 통해 쿼리 상태에 대한 세분화된 정보를 제공합니다 . 이 정보를 활용하기 위해 refetch 가 진행되는 동안 쿼리 컴포넌트가 다시 렌더링되도록 notifyOnNetworkStatusChange: true 옵션을 설정합니다.

 

 

import { NetworkStatus } from '@apollo/client';

function DogPhoto({ breed }) {

  const { loading, error, data, refetch, networkStatus } = useQuery(
    GET_DOG_PHOTO,
    {
      variables: { breed },
      notifyOnNetworkStatusChange: true,
    },
  );


  if (networkStatus === NetworkStatus.refetch) return 'Refetching!';
  if (loading) return null;
  if (error) return `Error! ${error}`;

  return (
    <div>
      <img src={data.dog.displayImage} style={{ height: 100, width: 100 }} />
      <button onClick={() => refetch()}>Refetch!</button>
    </div>
  );
}

 

notifyOnNetworkStatusChange: true 이 옵션을 활성화하면 networkStatus 속성에 의해서 = 세분화된 정보를 제공하는 것. 을 사용하지 않으려는 경우에도 그에 따라 loading 업데이트 값이 보장됩니다.

 

networkStatus 속성은 다양한 loading 상태를 나타내는 NetworkStatus enum 입니다. 

Refetch는 NetworkStatus.refetch 로 표시되며 polling 및 pagination 에 대한 값도 있습니다. 가능한 모든 loading 상태의 전체 목록은 소스 를 확인하세요 .

 

 

 

(아 무슨 말인지 모르겠다...)

 

 

 

 

 

 

Inspecting error states

생략..

 

 

 

 

 

 

 

Manual execution with useLazyQuery 

 

React가 useQuery 를 호출하는 컴포넌트를 렌더링할 때, Apollo Client 는 자동으로 해당 쿼리를 실행합니다. 그러나 사용자가 버튼을 클릭하는 것과 같은 다른 이벤트에 대한 응답으로 쿼리를 실행하려면 어떻게 해야 할까요?

 

 

useLazyQuery 후크는 컴포넌트 렌더링 외에 이벤트에 대한 응답으로 쿼리를 실행하는 데 적합합니다 . useQuery 와 달리 useLazyQuery 를 호출할 때 its associated query 를 즉시 실행하지 않습니다 . 대신 쿼리 를 실행할 준비가 될 때마다 호출 하는 쿼리 함수 를 결과 튜플에 반환합니다.

 

 

 

다음은 예입니다.

 

import React from 'react';
import { useLazyQuery } from '@apollo/client';

function DelayedQuery() {

  const [getDog, { loading, error, data }] = useLazyQuery(GET_DOG_PHOTO);

  if (loading) return <p>Loading ...</p>;
  if (error) return `Error! ${error}`;

  return (
    <div>
      {data?.dog && <img src={data.dog.displayImage} />}

      <button onClick={() => getDog({ variables: { breed: 'bulldog' } })}>
        Click me!
      </button>
    </div>
  );
}

 

useLazyQuery의 반환 튜플 에서 첫 번째 항목은 쿼리 함수이고 두 번째 항목은 useQuery 에서 반환한 것과 동일한 결과 object 입니다.

 

위에 표시된 것처럼 쿼리 함수에 옵션을 전달하는 것처럼, 옵션을 useLazyQuery 에 전달할 수 있습니다. 둘 다에 특정 옵션을 전달하면 쿼리 함수에 전달한 값이 우선합니다. 이것은 default 옵션을 useLazyQuery 에 전달하는 편리한 방법이고, 그리고나서 쿼리 함수에서 해당 옵션을 커스터마이징하는 편리한 방법입니다.

 

지원되는 옵션의 전체 목록은 API 참조 를 참조 하십시오 .

 

 

 

 

 

 

Setting a fetch policy (가져오기 정책 세팅)

기본적으로 useQuery 후크는 Apollo 클라이언트 캐시를 확인하여 요청한 모든 데이터가 이미 로컬에서 사용 가능한지 확인합니다. 모든 데이터  로컬에서 사용할 수 있는 경우, useQuery 는 해당 데이터를 반환하고 GraphQL 서버를 쿼리 하지 않습니다 .  cache-first 정책은 Apollo 클라이언트의 default fetch policy 입니다.

 

 

주어진 쿼리에 대해 다른 fetch policy 을 지정할 수 있습니다. 그렇게 하려면 다음 useQuery 에 대한 호출에 fetchPolicy 옵션을 포함하십시오 .

 

const { loading, error, data } = useQuery(GET_DOGS, {
  fetchPolicy: "network-only" // Doesn't check cache before making a network request
});

 

 

 

 

 

 

 

nextFetchPolicy

nextFetchPolicy 쿼리를 지정할 수도 있습니다. 그렇게 하면 쿼리의 첫 번째 실행에 fetchPolicy 가 사용되며 nextFetchPolicy 쿼리가 향후 캐시 업데이트에 응답하는 방식을 결정하는 데 사용됩니다.

 

const { loading, error, data } = useQuery(GET_DOGS, {
  fetchPolicy: "network-only",   // Used for first execution
  nextFetchPolicy: "cache-first" // Used for subsequent executions
});

 

예를 들어, 쿼리가 항상 초기 네트워크 요청을 하도록 하고 싶지만 그 이후에는 캐시에서 읽기가 편한 경우에 유용합니다.

 

 

 

 

 

 

 

 

 

지원되는 fetch policy

 

cache-first Apollo Client는 먼저 캐시에 대해 쿼리를 실행합니다. 요청된 모든 데이터가 캐시에 있으면 해당 데이터가 반환됩니다. 그렇지 않으면 Apollo Client가 GraphQL 서버에 대해 쿼리를 실행하고 캐싱 후 해당 데이터를 반환합니다.
애플리케이션에서 보낸 네트워크 요청 수를 최소화하는 데 우선 순위를 둡니다.
이것이 기본 가져오기 정책입니다.
cache-only Apollo Client 는 캐시에 대해서만 쿼리를 실행합니다. 이 경우 서버를 쿼리하지 않습니다.
캐시에 요청 된 cache-only모든 필드에 대한 데이터가 포함되어 있지 않으면 쿼리에서 오류가 발생합니다.
cache-and-network Apollo Client는 캐시 와 GraphQL 서버 모두에 대해 전체 쿼리를 실행 합니다. 서버 측 쿼리의 결과가 캐시된 필드를 수정하면 쿼리가 자동으로 업데이트됩니다.
캐시된 데이터를 서버 데이터와 일관성 있게 유지하는 데 도움이 되는 동시에 빠른 응답을 제공합니다.
network-only Apollo Client는 먼저 캐시를 확인 하지 않고 GraphQL 서버에 대해 전체 쿼리를 실행합니다 . 쿼리 결과  캐시에 저장됩니다.
서버 데이터와의 일관성을 우선시하지만 캐시된 데이터를 사용할 수 있을 때 거의 즉각적인 응답을 제공할 수 없습니다.
no-cache network-only쿼리 결과 가 캐시에 저장 되지 않는다는 점을 제외하면 과 유사 합니다.
standby 기본 필드 값이 변경될 때 cache-first이 쿼리가 자동으로 업데이트되지 않는다는 점을 제외하고 와 동일한 논리를 사용합니다 .  를 사용하여 이 쿼리를 수동으로 업데이트 할 수 있습니다 .refetchupdateQueries

 

 

 

 

 

 

 

 

 

useQuery 후크는 다음 옵션을 허용합니다 .

 

작업 옵션  
query
DocumentNode
gql템플릿 리터럴 을 사용하여 AST로 구문 분석된 GraphQL 쿼리 문자열 입니다.
useQuery쿼리가 후크에 대한 첫 번째 매개변수로 제공될 수 있으므로 후크에 대한 선택 사항 입니다. 구성 요소에 필요 합니다 Query.
variables
{ [key: string]: any }
쿼리를 실행하는 데 필요한 모든 GraphQL 변수를 포함하는 개체입니다.
개체의 각 키는 변수 이름에 해당하고 해당 키의 값은 변수 값에 해당합니다.
errorPolicy
ErrorPolicy
쿼리가 GraphQL 오류와 부분 결과를 모두 반환하는 응답을 처리하는 방법을 지정합니다.
자세한 내용은 GraphQL 오류 정책 을 참조하세요 .
기본값은 none, 쿼리 결과에 오류 세부 정보가 포함되지만 일부 결과 는 포함 되지 않음 을 의미합니다.
onCompleted
(data: TData | {}) => void
쿼리가 오류 없이 성공적으로 완료되었을 때(또는 errorPolicyis ignore이고 부분 데이터가 반환된 경우) 호출되는 콜백 함수입니다.
이 함수는 쿼리의 결과로 전달 data됩니다.
onError
(error: ApolloError) => void
쿼리에 하나 이상의 오류가 발생할 때 호출되는 콜백 함수입니다( errorPolicyis 제외 ignore).
이 함수는 발생한 오류에 따라 개체 또는 배열 ApolloError을 포함하는 개체에 전달됩니다.networkErrorgraphQLErrors
skip
boolean
인 경우 true쿼리가 실행 되지 않습니다 . 와 함께 사용할 수 없습니다 useLazyQuery.
이 속성은 Apollo Client의 React 통합의 일부이며 핵심 API 에서는 사용할 수 없습니다 .ApolloClient
기본값은 false입니다.
displayName
string
React 개발자 도구에 표시할 구성 요소의 이름입니다.
기본값은 Query입니다.
네트워킹 옵션
pollInterval
number
쿼리가 업데이트된 결과를 폴링하는 간격(밀리초)을 지정합니다.
기본값은 0(폴링 없음)입니다.
notifyOnNetworkStatusChange
boolean
인 경우 true진행 중인 쿼리의 관련 구성 요소는 네트워크 상태가 변경되거나 네트워크 오류가 발생할 때마다 다시 렌더링됩니다.
기본값은 false입니다.
context
Record<string, any>
Apollo Link 를 사용하는 경우 이 객체는 context링크 체인을 따라 전달 되는 객체의 초기 값입니다 .
ssr
boolean
서버 측 렌더링false 중에 쿼리 실행을 건너뛰려면 전달 합니다 .
client
ApolloClient
ApolloClient쿼리를 실행하는 데 사용할 인스턴스입니다 .
기본적으로 컨텍스트를 통해 전달된 인스턴스가 사용되지만 여기에서 다른 인스턴스를 제공할 수 있습니다.
캐싱 옵션
fetchPolicy
FetchPolicy
쿼리가 실행되는 동안 Apollo Client 캐시와 상호 작용하는 방식을 지정합니다(예: 서버에 요청을 보내기 전에 캐시에서 결과를 확인하는지 여부).
자세한 내용 은 가져오기 정책 설정 을 참조하세요 .
기본값은 cache-first입니다.
nextFetchPolicy
FetchPolicy
이 실행 후fetchPolicy 이 쿼리의 모든 실행에 사용할 것을 지정합니다 .
예를 들어, 이를 사용 하여 단일 실행을 사용한 후 또는 cache-first가져오기 정책 으로 다시 전환할 수 있습니다 .cache-and-networknetwork-only
returnPartialData
boolean
인 경우 캐시에 쿼리된 모든 필드 에 대한 결과가 포함되어 있지 않으면 쿼리가 캐시에서 부분true 결과를 반환할 수 있습니다.
기본값은 false입니다.
더 이상 사용되지 않는 옵션
partialRefetch
boolean
더 이상 사용되지 않습니다. 인 경우 쿼리 결과가 부분적으로 감지되면 쿼리가 발생합니다 true. refetch보다 일관된 가져오기 정책 적용 덕분에 Apollo Client 3에서는 이 옵션을 설정할 필요가 없습니다. 향후 릴리스에서 제거될 수 있습니다.
기본값은 false입니다.

 

 

 

 

 

 

 

 

결과

호출된 후 useQuery 후크는 다음 속성을 가진 결과 개체를 반환합니다. 이 개체에는 쿼리 결과와 함께 다시 가져오기, 동적 폴링 및 페이지 매김을 위한 몇 가지 유용한 기능이 포함되어 있습니다.

 

운영 데이터
data
TData
완료 후 GraphQL 쿼리의 결과를 포함하는 개체입니다.
이 값은 undefined쿼리로 인해 하나 이상의 오류가 발생하는 경우일 수 있습니다( 쿼리에 따라 다름 errorPolicy).
previousData
TData
이 쿼리 의 가장 최근 이전 실행 결과를 포함하는 개체 입니다.
이 값은 undefined쿼리의 첫 번째 실행인 경우입니다.
error
ApolloError
쿼리가 하나 이상의 오류를 생성하는 경우 이 개체에는 의 배열 graphQLErrors또는 단일 networkError. 그렇지 않으면 이 값은 undefined입니다.
자세한 내용은 작업 오류 처리 를 참조하십시오 .
variables
{ [key: string]: any }
쿼리에 제공된 변수를 포함하는 개체입니다.
네트워크 정보
loading
boolean
인 경우 true쿼리가 아직 진행 중이고 결과가 아직 반환되지 않았습니다.
networkStatus
NetworkStatus
쿼리와 연결된 요청의 현재 네트워크 상태를 나타내는 숫자입니다. 가능한 값을 참조하십시오.
notifyOnNetworkStatusChange옵션 과 함께 사용됩니다 .
client
ApolloClient
쿼리를 실행한 Apollo Client의 인스턴스입니다.
후속 쿼리를 수동으로 실행하거나 캐시에 데이터를 쓰는 데 유용할 수 있습니다.
called
boolean
이면 true연결된 지연 쿼리가 실행된 것입니다.
이 필드는 에서 반환한 결과 개체에만 있습니다 useLazyQuery.
도우미 기능
refetch
(variables?: Partial<TVariables>) => Promise<ApolloQueryResult>
선택적으로 new 를 전달하여 쿼리를 다시 실행할 수 있는 함수입니다 variables.
다시 가져오기가 네트워크 요청을 수행하도록 하기 위해 fetchPolicy로 설정됩니다 network-only(원래 쿼리 fetchPolicy가 네트워크 요청을 보장하는 no-cache또는 cache-and-network인 경우 제외).
다시 가져오기 도 참조하십시오 .
fetchMore
({ query?: DocumentNode, variables?: TVariables, updateQuery: Function}) => Promise<ApolloQueryResult>
페이지가 매겨진 목록 필드 에 대한 다음 결과 집합을 가져오는 데 도움이 되는 함수입니다 .
startPolling
(interval: number) => void
쿼리가 지정된 간격(밀리초)에서 다시 실행을 시작하도록 지시하는 함수입니다.
stopPolling
() => void
에 대한 이전 호출 후 폴링을 중지하도록 쿼리에 지시하는 함수입니다 startPolling.
subscribeToMore
(options: { document: DocumentNode, variables?: TVariables, updateQuery?: Function, onError?: Function}) => () => void
일반적으로 쿼리에 포함된 특정 필드를 구독하기 위해 구독 을 실행할 수 있는 기능입니다 .
이 함수는 구독을 종료하기 위해 호출할 수 있는 다른 함수를 반환합니다.
updateQuery
(previousResult: TData, options: { variables: TVariables }) => TData
후속 GraphQL 작업을 실행하지 않고 쿼리의 캐시된 결과를 업데이트할 수 있는 기능입니다.

 

 

 

 

 

 

 

 

https://www.apollographql.com/docs/react/data/queries/