Apollo Client는 상태관리 라이브러리다.
GraphQL api에서 데이터를 fetch 해오는 것을 가능하게 해주고
어플리케이션에서 로컬로 상태 관리할 수도 있게 해준다.
서버에 있는 데이터를 가지고 오는 것, 로컬에 있는 데이터를 관리하는 것
그리고 이 둘을 동기화 할 수 있다.
npx create-react-app movieql-client
$ yarn add @apollo/client graphql react-router-dom@6
세팅 완료 후
필요없는 파일들 지워준다.
기본 셋팅으로 2가지 파일을 만든 뒤 라우터 셋팅
const { ApolloClient, InMemoryCache } = require("@apollo/client");
const client = new ApolloClient({
uri: "http://localhost:4000/",
cache: new InMemoryCache(),
});
export default client;
client. js 작성한다
uri: "http://localhost:4000/"의 의미는 GraphQL 서버는 localhost:4000에서 돌아가고 있다.
cache: new InMemoryCache(),
cache strategy인데 캐싱에 대해서 다루는 거 같다.
그다음에 client가 잘 돌아가는 지 확인하기 위해서
훅을 사용할 것이다.
client.query({
query : gql`
{
allMovies {
title
}
}
`
}).then(data=> console.log(data));
이후에 index.js에 추가해주면
결과가 잘나온다 😆
import React from "react";
import ReactDOM from "react-dom/client";
import client from "./routes/client.";
import App from "./App";
import { ApolloProvider } from "@apollo/client";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</React.StrictMode>
);
index.js를 아폴로 감싸주고 client를 내려준다.
export default function Movies() {
const client = useApolloClient();
useEffect(() => {
client
.query({
query: gql`
{
allMovies {
title
}
}
`,
})
.then((res) => console.log(res));
},[client]);
return <div>hi</div>;
}
(모든 단계를 적는 명령형, 우리가 무엇을 원하는지 적는다.)
Provider는 애플리케이션 안의 모두가 이 client에 접근할 수 있게 해준다.
아까와 동일한 값이 나온다.
usestate를 이용하여 값을 꺼내줄 수 있지만, 매번 이렇게 쓰는건 지저분하다
매력적이고 멋지게 쓰기 위해서는 Hook을 사용해야한다.
const ALL_MOVIES = gql`
query getMovies{
allMovies {
title
id
}
}
`;
query getMovies <-써도 되고 안써도된다.
구분하거나 의미를 두기위해 쓴다.
바로 useQuery 이용하여 훅을 만든다.
useQuery는 여러 결과들을 전달해주는데
client: ApolloClient<any>;
observable: ObservableQuery<TData, TVariables>;
data: TData | undefined;
previousData?: TData;
error?: ApolloError;
loading: boolean;
networkStatus: NetworkStatus;
called: boolean;
이러한 내용들이 결과로 온다.
const result = useQuery(ALL_MOVIES);
result를 콘솔로그를 사용해 불러주면
결과값이 이렇게 온다.
loading이 true로 되어있는데 이는 아직 데이터를 받지 못한 상태이다.
(React Query와 유사하다)
false로 변하니 데이터값을 받아왔다.
React Query와 같은 방법으로
const {data, loading] = useQuery(ALL_MOVIES); 로 선언했다.
선언형 코드를 쓰게해주기때문에 매우 깔금했다.
(선언형 코드는 설명하기위한 코드만 적는 것을 말한다.
반면에 명령형:imperative 은 모든 단계의 코드를 적고 무엇을 원하는지 작성한다.)
export default function Movies() {
const { data, loading, error } = useQuery(ALL_MOVIES);
if (loading) {
return <h1>loading</h1>;
}
if (error) {
return <h1>Could not fetch :(</h1>;
}
return (
<div>
{data.allMovies.map((movie) => (
<li key={movie.id}>{movie.title}</li>
))}
</div>
);
}
로 완성한다.
useQuery로 매우 심플하게 되었다.
const ALL_MOVIES = gql`
query getMovies {
allMovies {
title
id
}
allTweets {
id
text
author {
fullName
}
}
}
`;
아폴로 사용한거와 동이할게 쿼리를 요청하여 받아올 수 있다.
결과도 이쁘게 잘나왔다.
코드가 매우 심플해져서 만족한다.
그다음 Link를 이용해
return (
<div>
<h1>Movies</h1>
{data.allMovies.map((movie) => (
<li key={movie.id}>
<Link to={`/movies/${movie.id}`}>{movie.title}</Link>
</li>
))}
</div>
);
적용시킨다.
그러면 param에 id값이 담긴다.
위 그림처럼 Variables 을 React에서 사용하려면 useQuery 훅을 사용해야한다.
const GET_MOVIE = gql`
query getMovie($movieId: String!) {
movie(id: $movieId) {
id
title
}
}
`;
export default function Movie() {
const { id } = useParams();
const { data, loading } = useQuery(GET_MOVIE, {
variables: {
movieId: id,
},
});
if (loading) {
return <h1>Fetching movie...</h1>;
}
console.log(data, loading);
return <div>{data.movie.title}</div>;
}
두번째 파라미터에 객체를 선언한 뒤 Variables라고 선언해준다.
$movieId와 movieId는 이름을 통일해야한다.
new InMemoryCache()에 의해 한번 들어갔던 곳을 다시 들어가면 로딩을 하지않는다.
왜냐하면 캐싱 되었기 때문에 바로 title을 보여준다.
이 확장을 사용하면 캐시를 더 쉽게 확인할 수 있다.
이를 통해 빠르게 GraphQL에 대하여 확인할 수 있다.
캐싱된 정보도 확인이 가능하다.
이렇게 아폴로의 캐싱 기능도 알아보았다.
리액트 쿼리와 비슷하다는 느낌을 받았다.