[Apollo Client] - Query

문규찬·2022년 8월 2일
0

출처 : http://apollo-kr.site/docs/fetcing/query

현 직장에서 Apollo Client 를 사용하고 있어 간략하게 살펴보고 넘어가려고 합니다.

[ Apollo Client ]

Apollo Client는 GrpahQL API를 호출하기 위해 사용되는 라이브러리입니다
사실, GraphQL API를 호출할 때, 반드시 Apollo Client와 같은 전용 클라이언트가 필요한 것은 아닙니다.

useQuery

useQuery 리액트 훅은 apollo 앱에서 쿼리를 구현하는 가장 중요한 API입니다.
리액트 컴포넌트 안에서 쿼리를 실행하기 위해서는 useQuery를 사용해야하고 이걸 graphql 쿼리문에 넘겨줘야합니다. 앱의 컴포넌트가 렌더링될 때 useQuery는 loading, error, data (등등) 라는 값을 가진 Apollo Client의 객체 덩어리 하나를 리턴받습니다.

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>
  );
}

캐싱

Apollo Client가 쿼리 결과를 서버에서 읽어올 때마다 이 결과값을 자동으로 로컬저장소 격인 캐시에 저장합니다. 이는 이 다음에 똑같은 쿼리를 콜 했을 때 결과를 획기적으로 빠르게 처리하도록 해줍니다.

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쿼리에 넘겨주고싶은 모든 변수가 담겨있는 객체입니다.

Dogs(드롭다운 컴포넌트 라고 가정)에서 'bulldog'이라는 값을 클릭해서 선택합시다. 그럼 불도그 사진이 렌더링 될거에요. 그 다음 아무거나 다른 사진을 클릭하시고, 다시 bulldog라는 값을 선택해보세요.아까 불러왔던 bulldog를 또 부르니 cache에서 빠르게 데이터를 가져온 것입니다. Apollo cache가 잘 작동한 것이죠.

캐시 업데이트

1. 풀링(Polling)

풀링은 정해진 주기로 쿼리를 주기적으로 발생시켜 거의 실시간으로 서버와 캐시를 동기화하는 방법입니다. 쿼리를 풀링하기 위해서는 pollInterval이라는 milliseconds 단위의 옵셔널한 값을 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으로 세팅하면 풀링이 발생하지 않는다는 점입니다.

2. 리페치(Refetch)

리페치는 특정 주기마다 쿼리 결과를 최신화하는것과 반대로, 사용자의 특정한 액션에 맞추어 쿼리 결과를 최신화하는 방법입니다.

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>
  );
}

버튼을 클릭하면 새로운 강아지의 사진으로 바뀐다는 사실에 주목하세요. Refetch를 사용하는 것은 최신 데이터를 가져오는 가장 확실한 방법입니다. 하지만 잘못 사용하면 refetch는 loading state에 관한 복잡한 문제의 시작일 지 모릅니다.

fetchPolicy

기본값으로 useQuery 훅은 요청한 데이터가 이미 로컬에 있는지 캐시를 확인합니다. 만약 모든 데이터가 캐시에 저장되어 있다면 굳이 graphql 서버에 요청하지 않고 캐시 데이터를 보내줍니다. 이걸 cache-first 정책이라고 합니다. 기본 정책이기도 하죠. 이것 말고도 다른 정책을 선택할 수 있는데 다음 코드와 같이 옵셔널하게 fetchPolicy라는 옵션을 useQuery를 콜 할 때 넣어주면 됩니다.

const { loading, error, data } = useQuery(GET_DOGS, {
  fetchPolicy: "network-only"
});

0개의 댓글