티스토리 뷰
# 시작
이번 포스팅에서는 Apollo Client를 이용해 이전에 구축한 서버에서 샘플 데이터를 가져옵니다.
필요한 의존성은 이전 포스팅(https://jee-goo.tistory.com/entry/React-Parcel-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%84%B1-FrontEnd-1)에서 전부 설치했기 때문에 바로 시작합니다.
# Apollo Client 및 Route 구성
다음 파일들을 생성합니다.
src/ApolloClient.tsx
import ApolloClient from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
const link = new HttpLink({
uri: 'http://localhost:8000/graphql' // `SpringBoot & Graphql 포스팅에서 구축한 서버의 URI`/graphql
});
const client = new ApolloClient({
link,
cache: new InMemoryCache()
});
export default client;
@ApolloClient
uri 속성에 `Spring Boot & Graphql` 포스팅에서 구성했던 서버의 uri와 EndPoint를 정의해주면 Query를 이용할 때 해당 uri로 데이터를 요청합니다.
이후 App.tsx에서 ApolloProvider의 client 속성에 이 컴포넌트를 넘겨주기만 하면 됩니다. 그럼 Query를 통해 데이터를 가져올 수 있습니다.
src/components/shared/Home.tsx
import React from 'react';
const Home = () => {
return (
<section id="intro" className="wrapper style1 fullscreen fade-up">
<div className="inner">
<h1>MyBlog</h1>
<p>Welcome to MyBlog</p>
</div>
</section>
)
}
export default Home;
src/components/shared/RouteComponent.tsx
import React from 'react'
import { Route } from 'react-router-dom';
import Home from './Home';
import Sample from '../sample/Sample';
const RouteComponent = () => {
return (
<div id="wrapper">
<Route exact={true} path="/" component={Home} />
<Route path="/Sample" component={Sample} />
</div>
)
}
export default RouteComponent;
@exact
path에 설정된 경로와 정확하게 똑같은 요청에만 정의된 컴포넌트를 보여줍니다.
src/components/shared/Sidebar.tsx
import React from 'react';
import { Link } from 'react-router-dom';
const Sidebar = () => {
return (
<section id="sidebar">
<div className="inner">
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/Sample">Sample</Link></li>
<li><Link to="/Sample2">Sample2</Link></li>
<li><Link to="/Sample3">Sample3</Link></li>
</ul>
</nav>
</div>
</section>
)
}
export default Sidebar;
@Link
<a> 태그 대신 사용하는 컴포넌트입니다.
<a> 태그의 href속성을 사용하게 되면 새로고침을 하게 됩니다.
새로고침을 하지 않고 라우팅을 하기 위해 사용합니다.
src/App.tsx를 다음과 같이 수정합니다.
import React, { Fragment } from 'react';
import { ApolloProvider as ApolloHooksProvider } from 'react-apollo-hooks';
import { BrowserRouter as Router } from 'react-router-dom';
import client from './ApolloClient';
import Sidebar from './components/shared/Sidebar';
import RouteComponent from './components/shared/RouteComponent';
const App = () => {
return (
<ApolloHooksProvider client={client}>
<Fragment>
<Router>
<Sidebar />
<RouteComponent />
</Router>
</Fragment>
</ApolloHooksProvider>
)
}
export default App;
@ApolloHooksProvider
react-apollo에서 useQuery라는 hook을 사용하기 위해 필요합니다.
client 속성에 위에서 만들었던 ApolloClient 컴포넌트를 넘겨줍니다.
# Sample Page 생성
Apollo 구성이 완료되었으니 이제 샘플 페이지를 생성합니다.
먼저 샘플 목록의 한 행을 나타낼 컴포넌트를 작성합니다.
src/components/sample/City.tsx
import React, { FunctionComponent } from 'react';
interface City {
id: number
name: string
population: number
}
const City: FunctionComponent<City> = (props) => {
return (
<tr>
<td>{props.id}</td>
<td>{props.name}</td>
<td>{props.population}</td>
</tr>
)
}
export default City;
@interface
FunctionComponent에 props의 타입을 명시합니다. 즉, City가 props의 타입이 되겠죠.
또한 interface City에 각 속성들의 타입을 명시하고 있습니다.
여기서 주의할 점은 tsconfig.json파일의 compilerOptions에서 strictNullChecks속성이 false라면 모든 타입은 null, undefined를 허용합니다.
반대로 true라면 null, undefined타입까지 고려하여 개발해야겠죠. 이런 경우에는 아래와 같이 타입을 정의합니다.
가능하다면 아래와 같이 개발하는 것이 작성할 때는 불편해도 결과적으로 좋습니다.
interface City {
id: number
name: string | undefined
}
이번엔 샘플 목록 컴포넌트를 생성합니다.
src/components/sample/CityList.tsx
import React, { FunctionComponent } from 'react';
import City from './City';
interface ICity {
id: number
name: string
population: number
}
interface ICityList {
cityList: [ICity]
}
const CityList: FunctionComponent<ICityList> = ({ cityList }) => {
const makeCityList = () => {
// (1)
return cityList.map((city: ICity) => (
<City
key={city.id}
id={city.id}
name={city.name}
population={city.population}
/>
));
}
return (
<section className="wrapper style2 fullscreen">
<h2>City List</h2>
<div className="table-wrapper">
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Population</th>
</tr>
</thead>
<tbody>
// (2)
{makeCityList()}
</tbody>
</table>
</div>
</section>
)
}
export default CityList;
@(1)
map은 javascript Array의 내장 함수입니다.
배열의 첫 번째 요소부터 마지막 요소까지 반복하며 콜백 함수를 실행하여 반환된 값들을 모아 새로운 배열로 반환합니다.
@(2)
(1)에서 정의한 함수를 실행하여 City 컴포넌트의 배열을 삽입합니다.
마지막으로 샘플 페이지를 만듭니다.
src/components/sample/Sample.tsx
import React from 'react';
import gql from 'graphql-tag';
import { useQuery } from 'react-apollo-hooks';
import CityList from './CityList';
const ALL_CITIES = gql`
query {
allCities {
id
name
population
}
}
`;
const Sample = () => {
const { data, error, loading } = useQuery(ALL_CITIES);
if(loading) return <span>Loading...</span>
if(error) return <span>error</span>
return (
<CityList cityList={data.allCities} />
)
}
export default Sample;
@gql
GraphQL 쿼리를 간편하게 작성하게 해주는 컴포넌트입니다.
이 같은 작성 방식을 Tagged Template Literal이라고 합니다. 궁금하다면 아래 링크를 참고하세요.
※작성된 쿼리는 `Spring Boot & Graphql` 포스팅에서 PlayGround로 테스트했던 쿼리입니다.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals
@useQuery
react-apollo의 Query를 Functional 하게 해주는 Hook입니다.
만일 react-apollo의 Query 컴포넌트를 사용하면 아래와 같습니다.
import React from 'react';
import gql from 'graphql-tag';
import { Query } from 'react-apollo';
import CityList from './CityList';
const allCities = gql`
query {
allCities {
id
name
population
}
}
`;
const Sample = () => {
return (
<Query query={allCities}>
{
({ loading, data, error }) => {
if(loading) return <span>loading...</span>
if(error) return <span>error</span>
return (
<CityList cityList={data.allCities} />
)
}
}
</Query>
)
}
export default Sample;
# 실행
샘플 페이지까지 완성되었으니 테스트할 시간입니다.
$ npm start
만약 이전 포스팅에서 안내한 Free Template가 동일하게 적용되어있다면 아래와 같은 Home 화면이 나타납니다.
Sample 메뉴를 클릭한 뒤 아래처럼 정상적으로 샘플 데이터 목록이 나오는지 확인합니다.
# 마치며
이번 포스팅까지 Spring Boot & Graphql <> React-Apollo로 구성된 애플리케이션을 간단하게 구성해보았습니다.
[나만의 블로그]라는 이름에서 알 수 있듯이 이 애플리케이션의 콘셉트는 블로그입니다.
블로그는 검색 포털 사이트에서 검색했을 때 노출되어야 하겠죠. 그렇다면 결국 SEO가 필요합니다.
그래서 다음 포스팅에서는 SSR을 적용해보겠습니다.
# GitHub
'프로젝트 > 나만의 블로그' 카테고리의 다른 글
Spring Boot & GraphQL & React-Apollo [게시판 만들기] (1) (1) | 2019.08.31 |
---|---|
Spring Boot & Nashorn으로 SSR [BE] (0) | 2019.08.25 |
React & Parcel 개발 환경 구성 [FE] (0) | 2019.08.24 |
Spring Boot & GraphQL (2) [BE] (2) | 2019.08.18 |
Spring Boot & GraphQL (1) [BE] (0) | 2019.08.18 |
- Total
- Today
- Yesterday
- 프로그래머스[힙]
- 웹 사이트 최적화
- 프로그래머스[해시]
- 실행 문맥
- Web
- 프로그래머스
- Jenkins
- graphql
- Spring Boot
- 프로그래머스[정렬]
- 동적계획법
- typescript
- Kubernetes
- PostgreSQL
- CRP 최적화
- CD
- 프로그래머스[이분탐색]
- Docker
- 프로그래머스[스택/큐]
- 프로그래머스[Lv1]
- react
- Pipeline
- Nashorn
- CI
- 알고리즘
- javascript
- Apollo
- Handshake
- JPA
- execution context
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |