Logo

[GraphQL/React] Apollo Hooks 소개/사용법

지난 달, Apollo Client에서 공개되어 현재 뜨거운 반응을 얻고 있는 Apollo Hooks에 대해서 알아보겠습니다.

Apollo Client가 생소하신 분들은 아래 포스팅를 먼저 보시고 이 포스팅로 돌아오시는 것을 추천드립니다.

Apollo Hooks?

Apollo Hooks는 Apollo Client로 React 앱을 개발할 때, GraphQL API를 호출할 수 있는 새로운 방법입니다. 기존에는 react-apollo 패키지에서 제공하는 <Query/><Mutation/>과 같은 HOC(Higher-Order Components)를 사용했었습니다.

기존에 React 앱에서 Apollo Client를 사용하여 GraphQL API를 호출하던 방법은 아래 포스팅를 참고 바랍니다.

하지만 React 개발의 패러다임을 흔든 React Hooks가 등장하면서, Apollo Client에서도 React Hooks를 사용하려는 시도들이 있었습니다. 그 중 대표적인 프로젝트가 react-apollo-hooks이며, 이 프로젝트로 부터 모티브를 얻어 Apollo의 공식 패키지로 Apollo Hooks(@apollo/react-hooks)가 출시되었습니다. (참고로 react-apollo-hooks 패키지는 Apollo Hooks가 출시되면서 deprecated 되었습니다.)

React Hooks에 대한 자세한 설명은 아래 포스팅를 참고바랍니다.

@apollo/react-hooks 패키지는 useQuery, useMutation, useApolloClient와 같은 React Hooks 함수를 제공하며, 이 함수들을 활용하면 React 앱에서 GraphQL API를 훨씬 쉽게 호출할 수 있습니다. 또한, 자연스럽게 클래스 대신에 함수 컴포넌트를 사용하게 되면서 코드의 가독성이나 유지보수 측면에서도 이점이 있습니다.

패키지 설치

Apollo Hooks를 사용하기 위해서 우선 자신의 리액트 프로젝트에 관련 패키지를 설치해야합니다.

$ npm i install @apollo/react-hooks apollo-cache-inmemory apollo-client apollo-link-http graphql graphql-tag
  • package.json
  "dependencies": {
    "@apollo/react-hooks": "^3.1.0",
    "apollo-cache-inmemory": "^1.6.3",
    "apollo-client": "^2.6.4",
    "apollo-link-http": "^1.5.16",
    "graphql": "^14.5.4",
    "graphql-tag": "^2.10.1",
    "react": "^16.9.0",
    "react-dom": "^16.9.0"
  },

Apollo Client 생성

먼저, apollo-client 패키지에서 임포트한 ApolloClient 생성자를 이용해서 Apollo Client를 생성하겠습니다. ApolloClient 생성자는 두 개의 옵션을 가진 객체를 인자로 받습니다. 첫번째, link 옵션으로는 원격으로 GraphQL API를 호출하기 위해서 GraphQL API의 endpoint 정보를 담은 HttpLink 객체를 설정해야 합니다. 여기서는 대륙/국가 데이터를 제공하는 공개된 GraphQL API의 endpoint 주소를 사용하였습니다. 두번째, cache 옵션으로는 가장 범용적으로 사용되는 InMemoryCache 객체를 설정합니다.

import ApolloClient from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { createHttpLink } from "apollo-link-http";

const client = new ApolloClient({
  link: createHttpLink({ uri: "https://countries.trevorblades.com" }),
  cache: new InMemoryCache(),
});

React에 Apollo Client 연결

다음으로, 위에서 생성한 ApolloClient 객체를 React에 연결해줘야 합니다. 앱 내에서 특정 React 컴포넌트만 GraphQL API 호출이 필요한 경우가 아닌 이상, 모든 React 컴포넌트에서 ApolloClient를 사용하도록 설정하는 것이 일반적입니다. 예를 들어, create-react-app으로 생성한 React 앱이라면 App.js 파일에서 이 작업을 해야합니다.

@apollo/react-hooks 패키지에서 임포트한 ApolloProvider 컴포넌트로 앱의 최상위 컴포넌트를 감싸줍니다. 이 때, ApolloProviderclient prop으로 위에서 생성한 ApolloClient 객체를 넘겨줘야 합니다. 이렇게 설정을 해주면, 앱 내의 모든 컴포넌트에서 GraphQL API 연동이 가능해집니다.

import React from "react";
import { ApolloProvider } from "@apollo/react-hooks";
import Continents from "./Continents";

function App() {
  return (
    <ApolloProvider client={client}>
      <h1>React + Apollo Hooks</h1>
      <Continents />
    </ApolloProvider>
  );
}

GraphQL API 호출

자, 이제 Apollo Hooks를 이용해서 GraphQL API를 호출할 차례입니다!

먼저, graphql-tag 패키지에서 제공하는 gql이라는 template literal tag를 사용해서 일반 자바스크립트 문자열을 GraphQL 구문으로 바꿔줍니다. 그 다음, @apollo/react-hooks 패키지에서 임포트한 useQuery React Hook 함수에 이 GraphQL 쿼리를 인자로 넘겨서 호출합니다. 그러면 useQuery 함수는 응답 데이터(data) 뿐만 아니라, 로딩 여부(loading)와 오류 데이터(error)까지 함께 리턴합니다.

서버로 부터 응답을 기다리는 동안에는 loading 프로퍼티 true이기 때문에 사용자에게 로딩 중이라는 메시지나 spinner 애니메이션 등을 표시해 줄 수 있습니다. 정상적으로 서버로 부터 응답 데이터가 도착하면 data 프로퍼티의 값을 읽어서 대륙 목록을 웹페이지에 출력합니다. 반대로 GraphQL API 호출이 실패된 경우에는 error 프로퍼티의 값을 읽어서 예외적인 UI 처리를 할 수 있습니다.

import React from "react";
import gql from "graphql-tag";
import { useQuery } from "@apollo/react-hooks";

const GET_CONTINENTS = gql`
  query {
    continents {
      code
      name
    }
  }
`;

function Continents() {
  const { loading, error, data } = useQuery(GET_CONTINENTS);
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error!(</p>;
  return (
    <ul>
      {data.continents.map(({ code, name }) => (
        <li key={code}>{name}</li>
      ))}
    </ul>
  );
}

export default Continents;

전체 코드

마치면서

이상으로 Apollo Hooks를 이용해서 React 앱에서 GraphQL API를 호출하는 방법에 대해서 아주 간단히 알아보았습니다. 예제에서 사용한 GraphQL API는 mutation은 제공하지 않기 때문에, useQuery 함수를 이용해서 query 호출하는 부분만 다루었습니다. Apollo Hooks에서 제공하는 다른 React Hooks 함수에 대해서는 아래 API reference 참고바라겠습니다.

관련 포스팅