: Apollo는 GraphQL API를 사용하기 좋은 방법이다.
REST API는 URL로 가서 JSON을 받아오지만
GraphQL은 query를 보내거나 mutation을 보내야한다.
설치
yarn add styled-components react-router-dom apollo-boost @apollo/react-hooks graphql
src/components/App.js
import React from "react";
import {HashRouter as Router, Route} from "react-router-dom";
import Detail from "../routes/Detail";
import Home from "../routes/Home";
function App() {
return (
<Router>
<Route exact path="/" component={Home}/>
<Route path="/:id" component={Detail}/>
</Router>
);
}
export default App;
src/routes/Detail.js
export default () => "Detail";
src/routes/Home.js
export default () => "Home";
: apollo-boost는 GraphQL Yoga처럼 이미 모든 걸 다 설정해 둔 package이다.
GraphQL Yoga가 바로 쓸 수 있게 준비를 다 해둔 server고 반대로 apollo-boost가 client 쪽이다.
src/apollo.js
import ApolloClient from "apollo-boost";
const client = new ApolloClient({
uri: "http://localhost:4000/"
});
export default client;
index.js
ApolloProvider로 감싸준다.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import {ApolloProvider} from "@apollo/react-hooks";
import client from "./apollo";
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById('root')
);
fetch나 JSON 같은 부분들을 전혀 하지 않고 useQuery를 사용하여 data를 가져올 수 있다.
src.routes/Home.js
import React from "react";
import {gql} from "apollo-boost";
import {useQuery} from "@apollo/react-hooks";
import styled from "styled-components";
import Movie from "../components/Movie";
const GET_MOVIES = gql`
{
movies{
id
medium_cover_image
}
}
`
export default () => {
const {loading, data} = useQuery(GET_MOVIES);
return (
<Container>
<Header>
<Title>Apollo movie</Title>
<Subtitle>I Love GraphQL</Subtitle>
</Header>
{loading && <Loading>Loading...</Loading>}
{!loading &&
data.movies &&
data.movies.map(m => <Movie key ={m.id} id={m.id}/>)
}
</Container>
)
}
src/components/Movie.js
import React from "react";
import {Link} from "react-router-dom";
export default ({id}) => (
<div>
<Link to={`/${id}`}>{id}</Link>
</div>
);
query에 variable이 있을 때 (예를 들어서 id) 그러면 그 query의 이름을 적어야 한다.
(Apollo, React, GraphQL, React Apollo을 위한 이름)
query에서 이름부분은 Apollo를 위한 것이다. Apollo가 변수의 type을 검사하도록 도와준다.
안에 movie(id){} 부분은 서버로 가는 query이다.
src/routes/Detail.js
import React from "react";
import {useQuery} from "@apollo/react-hooks";
import { useParams } from "react-router-dom";
import { gql } from "apollo-boost";
const GET_MOVIE = gql`
query getMovie($id: Int!) {
movie(id: $id){
id
title
medium_cover_image
description_intro
}
}
`;
export default () => {
let {id} = useParams();
const {loading, data} = useQuery(GET_MOVIE, {
variables: {id: parseInt(id)},
});
if(loading){
return "loading";
}
if(data && data.movie){
return data.movie.title;
}
};
한번 눌렀던 id를 다시 누르면 loading이 뜨지 않고 바로 제목이 보인다.
React Apollo는 cache를 가지고 있다.
만약 React Apollo가 뭔가를 얻으면 그거를 저장해 둔다.
const {loading, data} = useQuery(GET_MOVIE, {
variables: {id: parseInt(id)},
});
return (
<Container>
<Column>
>>>> <Title>{data.movie.title}</Title>
```
위의 부분은
` <Title>{loading? "Loading...": data.movie.title}</Title>`
이렇게 작성해야한다.
### Optional Chaining
` bg={data && data.movie ? data.movie.medium_cover_image : ""}`
이것을 Optional Chaining을 사용해서 바꾸면
`bg={data?.movie?.medium_cover_image}`
### Local State
만약 local state를 바꾸고 싶다면 client에 mutation을 생성해서 바꿀 수 있다.
Apollo에게 mutation이 @client에 있다고 알려줘야한다.
```js
const LIKE_MOVIE = gql`
mutation likeMovie($id: Int!) {
likeMovie(id: Id) @client
}
`;
apollo.js
Mutation: {
likeMovie: (_, { id }, { cache }) => {
cache.writeData({
id: `Movie:${id}`,
data: {
isLiked: true,
},
});
},
},
새로운 필드를 movie resolver에서 생성했다는 것
이것은 API랑 같은 이름이어야한다.
그 다음에 mutation을 만들었다.
apollo.js
const client = new ApolloClient({
uri: "http://localhost:4000",
resolvers: {
Movie: {
isLiked: () => false,
},
like 버튼 누르기전 isLiked는 false
like 버튼 누르면 isLiked는 true