- 본 시리즈에서는 How to GraphQL의 Tutorial 문서들을 차례대로 번역합니다.
- 이 글은 GraphQL React + Apollo Tutorial - Queries: Loading Links을 번역한 글입니다.
- 본 시리즈는 GraphQL Basic and Advanced 시리즈와 GraphQL-Node Tutorial 시리즈에서 이어집니다. GraphQL을 처음 접하는 분들은 해당 시리즈를 먼저 읽고 오시는 것을 추천드립니다.
- 오역 또는 의역이 있을 수 있습니다. 양해 부탁드리며, 수정이 필요한 부분은 댓글로 요청해주세요.
어플리케이션에서 구현할 첫번째 기능은 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
를 가져와서 해당 링크의 description
과 url
을 렌더링하는 간단한 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개 링크를 표시할 겁니다.
다음으로, 데이터베이스에 저장된 실제 링크를 불러오겠습니다. 제일 먼저 할 일은 API로 전송할 GraphQL 쿼리를 정의하는 것입니다.
아래와 같은 모습입니다.
{
feed {
links {
id
createdAt
description
url
}
}
}
Playground를 사용하면, 어플리케이션 스키마에 따라 쿼리를 작성하여 전송하고, GraphQL 서버로부터 결과를 반환받을 수 있을 겁니다. 하지만, 자바스크립트 코드 상에서는 어떻게 사용해야 할까요?
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 함수 내에서 사용할 수 있게 해줍니다.
일반적으로, 데이터를 불러오는 로직을 더하는 과정은 매번 아래와 같은 식으로 유사할 것입니다.
gql
파서(Parcer) 함수를 사용하여 자바스크립트 상수 형태로 쿼리 작성
props
로 GraphQL 쿼리를 전달한 <Query />
컴포넌트를 사용
컴포넌트의 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> )
자, 위 코드에서는 무슨 일이 일어나고 있는 걸까요?
우선, FEED_QUERY
라는 자바스크립트 상수를 선언하여 쿼리를 저장합니다. gql
함수는 GraphQL 코드를 포함하는 평문 String을 파싱하는 데에 사용됩니다. 백틱(``) 문법이 낯설다면, Tagged Template Literal과 관련된 이 문서를 읽어보시기 바랍니다.
마지막으로, 반환되는 코드를 <Query />
컴포넌트로 감쌉니다. 여기서 FEED_QUERY
는 props
로 전달됩니다.
참고:
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
는 네트워크 요청의 상태에 대한 정보를 스스로 제공합니다.
loading
: 요청이 현재 이루어지고 있으며 응답이 반환되지 않았다면 항상 true
를 가집니다.
error
: 요청이 실패했을 경우, 이 필드는 무엇이 잘못되었는지에 관한 정보를 포함합니다.
data
: 서버로부터 반환된 실제 데이터입니다. 지금의 경우, 여기에는 Link
요소로 이루어진 리스트를 나타내는 links
속성이 들어있습니다.
사실, 주입된
props
는 보다 많은 기능을 가지게 됩니다. API Overview에서 더 자세히 배울 수 있습니다.
됐습니다! 이제 기존과 동일한 화면을 볼 수 있을 겁니다.
참고:
http://localhost:4000
를 보여주는 브라우저 화면에 오류와 함께 아무 것도 나오지 않는다면, 서버를 켜는 것을 잊은 것일 수도 있습니다. 이 어플리케이션이 작동하려면 서버 또한 작동 중이어야 합니다. 따라서, 터미널에서 두 개의 프로세스가 실행중이어야 합니다. 하나는 서버이고, 또 하나는 React 어플리케이션입니다. 서버를 시작하려면,server
디렉토리로 이동한 뒤yarn start
를 실행하세요.
Quiz
React와 Apollo를 사용하여 데이터를 불러오는 선언적인 방법으로 적절한 것은?
graphql
고차 컴포넌트를 사용한다<Query />
컴포넌트를 사용하고, GraphQL 쿼리를props
로 전달한다.- 자바스크립트
fetch
를 사용하고, 요청 본문을 통하여 쿼리를 전달한다.XMLHTTPRequest
를 사용하고, 요청 본문을 통하여 쿼리를 전달한다.