2021. 12. 21. 00:03ㆍReactJS/Information
해당 글에는 GraphQL이 나오니 모른다면 이해가 어려울 수 있다.
아래 링크를 통해 먼저 알고 가도록 하자.
[ Graph QL ]
[ 완성 코드 보러가기 ]
[ 참고문서 : React-Query ]
→ 실제 사용은 되지 않으나 사용법이 매우 유사함.
라이브러리
React.js에서 GraphQL 서버와 통신할 때 주로 사용되는 라이브러리는 크게 3가지가 있다.
- Relay
퍼포먼스, 네트워크 트래픽 최적화 / 높은 러닝커브 - Apollo Client
데이터 캐싱, UI 업데이트 - urql
단순성과 확장성에 중점, React에 포커스 되어 있음, Relay, Apllo Client 보다 이후에 나왔음.
위 3개의 라이브러리에 모두 장단점이 있으니 찾아서 사용하면 될텐데, 이 글에서는 Apollo Client를 이용하였다.
Apollo Client
Apollo Client(이하 React Apollo)에서는 사용법이 2가지로 나뉜다.
Hooks 사용/미사용 으로 나뉘는데, 이 글에서는 Hook을 사용하는 것으로 채택하여 작성한다.
기본 설정
create-react-app으로 React.js App을 하나 생성해주고 아래 의존성을 설치해주도록 하자.
(이 글에서는 보다 좋은 설명을 위해 Typescript를 이용하였다.)
# npm
npm install apollo-boost @apollo/react-hooks graphql
# yarn
yarn add apollo-boost @apollo/react-hooks graphql
src/index.tsx를 아래와 같이 설정해주도록 하자.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {ApolloClient, ApolloProvider, InMemoryCache} from "@apollo/react-hooks";
const client = new ApolloClient({
uri: 'http://localhost:8080',
cache: new InMemoryCache()
})
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
(react-redux와 같이 사용할 경우 ApolloProvider를 store-provider 위에 감싸면 된다.)
여기서 client에 InMemoryCache는 캐싱처리에 대한 내용을 설정할 수 있다.
(참고 : https://www.apollographql.com/docs/react/caching/cache-configuration/)
uri는 localhost에 올라와있는 Spring boot GraphQL 서버를 이용했으며, 만약 Spring boot GraphQL 서버를 띄우지 못하는 환경이라면 GraphQL Fake Api 를 구글링하면 많이 나올테니, 그 서버를 이용하면 된다.
그 후 Query를 작성해주면 된다.
queries/Queries.ts
import {gql} from "graphql-tag";
export const __GET_POST__ = gql`
query {
getPost {
title
}
}
`
이 때 getPost 쪽에서 빨간줄이 나올 수 있는데, 이는 Schema와 Type을 정의하지 않아서 그렇다.
이런 경우에 나는 IntelliJ IDEA를 사용하고 있어 자동적으로 지원을 해주고 있는데, 다른 개발 툴에서는 어떻게 적용하는지에 대해서는 찾아봐야 한다.
(검색어 : .graphqlconfig generate, schema.graphql auto generate)
IntelliJ의 경우 .graphqlconfig를 root 경로에 작성해주게 되면 원격 서버에 있는 Schema와 Type을 전부 자동으로 정의해준다.
.graphqlconfig
{
"name": "y0ngha GraphQL Post & Comment Schema",
"schemaPath": "./schema.graphql",
"extensions": {
"endpoints": {
"Default GraphQL Endpoint": {
"url": "http://localhost:8080/graphql",
"headers": {
"user-agent": "JS GraphQL"
},
"introspect": true
}
}
}
}
위처럼 작성하고, Auto generation을 작동시킨다면, schemaPath에 정의되어있는 경로 & 파일명에 자동으로 작성된다.
(다시 한번 말하지만 IntelliJ IDEA 기준으로 다른 개발 툴에서는 어떻게 작동되는지에 대해서 찾아봐야 한다.)
(이게 introspect 기능인가?)
여기까지 했으면 이제 빨간줄은 사라졌을거고, 테스트 컴포넌트를 만들어 한번 테스트해보자.
Post.tsx
import React from "react"
import { useQuery } from "@apollo/react-hooks";
import {__GET_POST__} from "../queries/Queries";
interface GetPostQuery {
getPost: GetPost[]
}
interface GetPost {
title: string
}
function Post() {
const { loading, error, data } = useQuery<GetPostQuery>(__GET_POST__)
console.log(error, data)
return (
<>
{
loading ? "Loading..." : ""
}
{
error ? error.message : ""
}
{
data?.getPost.length !== 0 &&
data?.getPost.map((it: GetPost) => {
return (
<>
{it.title}<br/>
</>
)
})
}
</>
)
}
export default Post
(interface의 경우 다른 폴더를 생성해 한 폴더 내에서 관리를 해주는것이 좋으나, 테스트 목적으로 생성된 프로젝트기 때문에 컴포넌트 내부에 선언해줬다.)
apollo에서 지원하는 useQuery를 사용하면 되는데, 이것은 react-query의 사용법과 매우 유사하다.
(react-query 사용법은 스크롤을 맨 위로 올리면 링크가 있다.)
[ 공식 문서에서 Apollo Use Query에 대해서 살펴보기 ]
위와 같이 Post 컴포넌트를 렌더링 하게 되면, title이 보이게 될 것이다.
useQuery를 이용해 데이터를 읽었으니, 이제 useMutation을 통해 데이터를 패치 해보도록 하자.
데이터를 조작하기 위해 Post 컴포넌트를 간단하게 수정했다.
버튼을 누르게 되면 해당 글을 삭제하고, 리렌더링 하는 기능을 만들 것이다.
queries/Queries.ts
import {gql} from "graphql-tag";
export const __GET_POST__ = gql`
query {
getPost {
id,
title
}
}
`
Post.tsx
import React from "react"
import { useQuery } from "@apollo/react-hooks";
import {__GET_POST__} from "../queries/Queries";
interface GetPostQuery {
getPost: GetPost[]
}
interface GetPost {
id: number,
title: string
}
function Post() {
const { loading, error, data, refetch } = useQuery<GetPostQuery>(__GET_POST__)
console.log(error, data)
return (
<>
{
loading ? "Loading..." : ""
}
{
error ? error.message : ""
}
{
data?.getPost.length !== 0 &&
data?.getPost.map((it: GetPost) => {
return (
<div className={"post"} key={it.id}>
<span key={`${it.id}-span`}>{it.title}</span><button key={`${it.id}-button`}>Delete</button><br/>
</div>
)
})
}
</>
)
}
export default Post
저 button에다가 click Event를 부여해 업데이트를 진행할 것이다.
queries/Queries.ts
import {gql} from "graphql-tag";
export const __GET_POST__ = gql`
query {
getPost {
id,
title
}
}
`
export const __DELETE_POST__ = gql`
mutation DeletePostById($id: Int!){
deletePostById(id: $id)
}
`
Post.tsx
import React, {useCallback} from "react"
import {useMutation, useQuery} from "@apollo/react-hooks";
import {__DELETE_POST__, __GET_POST__} from "../queries/Queries";
interface GetPostQuery {
getPost: GetPost[]
}
interface GetPost {
id: number,
title: string
}
function Post() {
const {loading, error, data, refetch} = useQuery<GetPostQuery>(__GET_POST__)
const [dataDelete] = useMutation(__DELETE_POST__)
console.log(error, data)
const fetchDataDelete = useCallback(async (id: number) => {
const result = await dataDelete({
variables: {
id: id
}
})
refetch()
console.log(result)
}, [])
return (
<>
{
loading ? "Loading..." : ""
}
{
error ? error.message : ""
}
{
data?.getPost.length !== 0 &&
data?.getPost.map((it: GetPost) => {
return (
<div className={"post"} key={it.id}>
<span key={`${it.id}-span`}>{it.title}</span>
<button key={`${it.id}-button`} onClick={async () => { await fetchDataDelete(it.id)}}>Delete</button>
<br/>
</div>
)
})
}
</>
)
}
export default Post
위와 같이 작성해주면, 버튼을 누를때마다 사라지는 것을 볼 수 있다.
만약, query도 위와 같이 조건을 주고 갖고오고 싶다면 아래와 같이 작성하면 된다.
export const __GET_POST_BY_ID_ = gql`
query GetPostById($id: Int!) {
getPostById(id: $id) {
id,
title
}
}
`
refetch를 이용해 다시 호출할 때 변수를 설정해줄 수 있다.
마치며
React.js에서 GraphQL을 적용하는 것은 생각보다 힘들었다.
아직 모르는것도 많고, 설정에 대해 미숙해 그러는 것 같다.
사실 이번 글은 단순히 사용법만 작성한 것이다.
더 공부해서 조금 더 심화적인 부분을 알아가야 잘 사용할 수 있을 것 같다.
우선 하나는 확실한게, 공통 Type을 정의해 CUD에서 성공했는지 실패했는지를 관리했었어야 했을 것 같다.
참고문서)
https://www.apollographql.com/docs/react/data/error-handling/
https://www.daleseo.com/graphql-apollo-remote-schemas/
https://d2.naver.com/helloworld/4245995
https://velog.io/@bangina/Apollo-client-GraphQL-React.js-%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83
'ReactJS > Information' 카테고리의 다른 글
[React.js] React + Typescript 테스트 코드 작성하기 (0) | 2022.01.04 |
---|---|
[React.js] React-Testing-Library 사용하기 (0) | 2022.01.03 |
[React.js] Lazy Image Component (0) | 2021.12.15 |
[React.js] React Query(useQuery, useMutation) (0) | 2021.12.14 |
[React.js] createPortal 사용하여 DOM을 원하는 요소 안으로 옮기 (0) | 2021.12.11 |