GraphQL React + Apollo Tutorial - 3. Query: 링크 불러오기

cadenzah·2020년 2월 24일
5
post-thumbnail

쿼리: 링크 불러오기

React 컴포넌트 준비하기

어플리케이션에서 구현할 첫번째 기능은 Link 요소의 리스트를 불러오고 표시하는 것입니다. 프로젝트의 React 컴포넌트 구조를 쭉 돌아본 뒤, 우선 하나의 링크를 렌더링하는 컴포넌트부터 시작하겠습니다.

components 디렉토리에 Link.js 파일을 새로 만들고, 아래의 코드를 작성합니다.
($ .../hackernews-react-apollo/src/components/Link.js)

import React, { Component } from 'react'

class Link extends Component {
    render() {
    return (
      <div>
        <div>
          {this.props.link.description} ({this.props.link.url})
        </div>
      </div>
    )
  }
}

export default Link

props에서 link를 가져와서 해당 링크의 descriptionurl을 렌더링하는 간단한 React 컴포넌트입니다. 식은 죽 먹기죠! 🍵

다음으로, 링크들의 리스트를 렌더링하는 컴포넌트를 구현하겠습니다.

다시, components 디렉토리에서 LinkList.js 파일을 새로 만들고, 아래의 코드를 작성합니다.
($ .../hackernews-react-apollo/src/components/LinkList.js)

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

class LinkList extends Component {
  render() {
    const linksToRender = [
      {
        id: '1',
        description: 'Prisma turns your database into a GraphQL API 😎',
        url: 'https://www.prismagraphql.com',
      },
      {
        id: '2',
        description: 'The best GraphQL client',
        url: 'https://www.apollographql.com/docs/react/',
      },
    ]

    return (
      <div>{linksToRender.map(link => <Link key={link.id} link={link} />)}</div>
    )
  }
}

export default LinkList

여기서 우리는 컴포넌트 설정이 제대로 작동하는지 확인하기 위한 목적으로 로컬 더미 데이터를 사용했습니다. 곧, 서버로부터 불러온 실제 데이터로 대체할 겁니다. 참으시오, 젊은 파다완이어!

App.js 파일을 열고, 아래의 내용으로 코드를 대체하여 설정을 마무리합니다.
($ .../hackernews-react-apollo/src/components/App.js)

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

class App extends Component {
  render() {
    return <LinkList />
  }
}

export default App

어플리케이션을 실행하여 모든 것이 제대로 작동하는지 확인합니다! 이제 어플리케이션은 linksToRender 배열에 저장된 2개 링크를 표시할 겁니다.

GraphQL 쿼리 작성하기

다음으로, 데이터베이스에 저장된 실제 링크를 불러오겠습니다. 제일 먼저 할 일은 API로 전송할 GraphQL 쿼리를 정의하는 것입니다.

아래와 같은 모습입니다.

{
  feed {
    links {
      id
      createdAt
      description
      url
    }
  }
}

Playground를 사용하면, 어플리케이션 스키마에 따라 쿼리를 작성하여 전송하고, GraphQL 서버로부터 결과를 반환받을 수 있을 겁니다. 하지만, 자바스크립트 코드 상에서는 어떻게 사용해야 할까요?

Apollo 클라이언트와 함께 쿼리 사용하기

Apollo를 사용하면, 두 가지 방법 중 하나로 서버에 쿼리를 전송할 수 있습니다.

첫번째 방법은 ApolloClient.query() 메서드를 직접 사용하는 것입니다. 데이터를 불러올 수 있는 아주 직접적인 방법이며, 응답 결과는 프라미스 형태로 받게 됩니다.

실질적인 예시는 아래와 같습니다.

client.query({
  query: gql`
    {
      feed {
        links {
          id
        }
      }
    }
  `
}).then(response => console.log(response.data.allLinks))

하지만, React를 사용시 보다 선언적인 방법은 Apollo의 새로운 Render Prop API를 사용하여, 컴포넌트만으로 GraphQL 데이터를 관리하는 것입니다.

이 방식을 적용하여 데이터를 불러오면, props에 GraphQL 쿼리를 전달하는 것만으로 <Query /> 컴포넌트가 알아서 데이터를 불러온 뒤 컴포넌트의 Render Prop 함수 내에서 사용할 수 있게 해줍니다.

일반적으로, 데이터를 불러오는 로직을 더하는 과정은 매번 아래와 같은 식으로 유사할 것입니다.

  1. gql 파서(Parcer) 함수를 사용하여 자바스크립트 상수 형태로 쿼리 작성

  2. props로 GraphQL 쿼리를 전달한 <Query /> 컴포넌트를 사용

  3. 컴포넌트의 Render Prop 함수를 거쳐서 주입된 쿼리 결과에 접근

LinkList.js 파일을 열고, 아래의 쿼리를 파일 최상단에 추가합니다.
($ .../hackernews-react-apollo/src/components/LinkList.js)

const FEED_QUERY = gql`
  {
    feed {
      links {
        id
        createdAt
        url
        description
      }
    }
  }
`

또한 return 문을 아래 내용으로 대체합니다.
($ .../hackernews-react-apollo/src/components/LinkList.js)

return (
  <Query query={FEED_QUERY}>
    {() => linksToRender.map(link => <Link key={link.id} link={link} />)}
  </Query>
)

자, 위 코드에서는 무슨 일이 일어나고 있는 걸까요?

  1. 우선, FEED_QUERY라는 자바스크립트 상수를 선언하여 쿼리를 저장합니다. gql 함수는 GraphQL 코드를 포함하는 평문 String을 파싱하는 데에 사용됩니다. 백틱(``) 문법이 낯설다면, Tagged Template Literal과 관련된 이 문서를 읽어보시기 바랍니다.

  2. 마지막으로, 반환되는 코드를 <Query /> 컴포넌트로 감쌉니다. 여기서 FEED_QUERYprops로 전달됩니다.

참고: linksToRender를 함수 결과값으로 반환하고 있는데, 이는 <Query />가 제공하는 Render Prop 함수를 사용하기 위함입니다.

이 코드가 제대로 작동하려면, 대응하는 의존성을 추가해야 합니다. 파일 최상단, import 구문에 이어서 아래의 두 줄을 추가합니다.
($ .../hackernews-react-apollo/src/components/LinkList.js)

import { Query } from 'react-apollo'
import gql from 'graphql-tag'

아주 좋아요! 이렇게만 하면 데이터를 불러오는 코드는 다 완성한 겁니다. 믿겨지나요? 하지만 보시다시피, 아직 서버 데이터를 받아오고 있지 않죠. 제대로 만들어봅시다! 🤩

드디어 더미 데이터를 제거하고, 서버에서 불러온 실제 링크들을 렌더링할 수 있습니다. <Query />의 Render Prop 함수 덕분이지요.

동일하게 LinkList.js 파일 내에서 LinkList 컴포넌트를 아래와 같이 갱신합니다.
($ .../hackernews-react-apollo/src/components/LinkList.js)

class LinkList extends Component {
  render() {
    return (
      <Query query={FEED_QUERY}>
        {({ loading, error, data }) => {            // 수정
          if (loading) return <div>Fetching</div>   // 수정
          if (error) return <div>Error</div>        // 수정
    
          const linksToRender = data.feed.links     // 수정
    
          return (
            <div>
              {linksToRender.map(link => <Link key={link.id} link={link} />)}
            </div>
          )
        }}
      </Query>
    )
  }
}

위 코드를 제대로 이해하고 넘어가도록 하죠. 예상하셨듯이, 컴포넌트의 Render Props 함수 내에 Apollo가 몇 가지 props를 주입했습니다. 이 props는 네트워크 요청의 상태에 대한 정보를 스스로 제공합니다.

  1. loading: 요청이 현재 이루어지고 있으며 응답이 반환되지 않았다면 항상 true를 가집니다.

  2. error: 요청이 실패했을 경우, 이 필드는 무엇이 잘못되었는지에 관한 정보를 포함합니다.

  3. data: 서버로부터 반환된 실제 데이터입니다. 지금의 경우, 여기에는 Link 요소로 이루어진 리스트를 나타내는 links 속성이 들어있습니다.

사실, 주입된 props는 보다 많은 기능을 가지게 됩니다. API Overview에서 더 자세히 배울 수 있습니다.

됐습니다! 이제 기존과 동일한 화면을 볼 수 있을 겁니다.

참고: http://localhost:4000를 보여주는 브라우저 화면에 오류와 함께 아무 것도 나오지 않는다면, 서버를 켜는 것을 잊은 것일 수도 있습니다. 이 어플리케이션이 작동하려면 서버 또한 작동 중이어야 합니다. 따라서, 터미널에서 두 개의 프로세스가 실행중이어야 합니다. 하나는 서버이고, 또 하나는 React 어플리케이션입니다. 서버를 시작하려면, server 디렉토리로 이동한 뒤 yarn start를 실행하세요.

Quiz

React와 Apollo를 사용하여 데이터를 불러오는 선언적인 방법으로 적절한 것은?

  • graphql 고차 컴포넌트를 사용한다
  • <Query /> 컴포넌트를 사용하고, GraphQL 쿼리를 props로 전달한다.
  • 자바스크립트 fetch를 사용하고, 요청 본문을 통하여 쿼리를 전달한다.
  • XMLHTTPRequest를 사용하고, 요청 본문을 통하여 쿼리를 전달한다.

0개의 댓글