2022.07.04 수정되었습니다
혹시 정정해야 할 부분이 있다면 댓글로 알려주시면 감사하겠습니다 !
추가로 학습 후 수정/보완 할 예정입니다.
데이터 통신을 통해 받아온 상태값을 관리하는 방법에 있어서 두가지를 비교해보고자 한다.
그동안 Redux
에서 REST API
사용으로 인해 발생하는 over-fetching
문제에 대한 해결법을 알아보다 알게 된 apollo client
에 대해 알아보자.
위 이미지를 기반한, 데이터를 받아와 상태를 관리할 때의 redux의 상태관리 절차를 보자면,
UI(component)
가 DOM
위에 그려지기 전에 action creator
는 fetch
요청에 필요한 정보(url, method 등)를 액션과의 dispatch
를 통해 redux
에게 알려준다.REST API
를 통해 미리 선언해 놓은 엔드포인트를 통해 전달 받은 데이터는 JSON형식으로 반환된다.fetch
작업이 완료되었다고 action
을 통해 redux
에게 알려준다.reducer
를 통해 받은 데이터를 사용해 redux
는 store
에 있는 state
트리를 업데이트한다.여기서 만약 부모 컴포넌트 안에 있는 자식 컴포넌트의 state
를 업데이트 해야 하는 상황이라면, 부모 컴포넌트에게서 필요한 데이터를 props
로 전달받아서 업데이트 하는 과정이 추가된다 😮💨
자식 컴포넌트 한개를 렌더링 하기 위해서 너무나 복잡한 절차가 필요하고, 이 외에도 REST API
의 over-fetching
이나 under-fetching
의 문제까지..
Apollo Client
는GraphQl
기반의 라이브러리로,
클라이언트 어플리케이션의GraphQl
과 데이터 교환을 돕는다
우선 두괄식으로 얘기해보자면,
Apollo Client
를 사용하게 되면,
Redux
처럼 따로 action, reducer, type 설정 등의 부과적인 작업 없이 데이터를 불러오는 것이 가능해진다.
또한 필요한 데이터만 선택적으로 가져오는 것이 가능해진다!
간단하게 작업해볼 수 있는 자료를 찾아서, 정리해보기로 했다.
미리 생성한 리엑트 프로젝트에 Apollo Client
를 사용하기 위해선 두가지 패키지 설치가 필요하다.
npm install @apollo/client graphql
@apollo/client
: Apllo에서 제공하는 GraphQl 클라이언트 패키지ApolloProvider
등을 제공한다.graphql
: GraphQl스펙을 javascript언어로 구현한 패키지Apollo Client
를 생성할 때에는 GraphQl API
의 접속정보 설정이 필요하다.
import { ApolloClient } from '@apollo/client';
export const client = new ApolloClient({
uri: "https://countries.trevorblades.com",
});
위 uri를 접속해보면, schema에 대한 정보가 있다.
그 중에 내가 사용할 continent
에 대한 정보를 보면,
이렇게 세가지 필드가 들어있는데,
REST API
와 다르게 GraphQl API
를 사용하면 원하는 값들만 가져와서 사용할 수 있다.
(REST API
를 사용하면, 모든 값을 가져와서 용도에 맞게 조작하는 과정이 필요하다)
import React from 'react';
import { ApolloProvider } from '@apollo/client';
import { client } from 'apollo/client';
import Home from 'components/home';
function App() {
return (
<ApolloProvider client={client}>
<Home />
</ApolloProvider>
);
}
export default App;
ApolloProvider
는 Context API의 Provider
처럼 최상위 컴포넌트로
위치시켜서 사용하면, 어느 위치에서든 Apollo client에 접근이 가능해진다.
import React from 'react';
import { gql, useQuery } from '@apollo/client';
const GET_CONTINENTS = gql`
query {
continents {
code
name
}
}
`
function Home() {
const { loading, error, data } = useQuery(GET_CONTINTNES);
const datas = data?.continents.length !== 0 ? data?.continents : null;
if(loading) return <Loading />;
if(error) return <Error />;
return (
<>
<h2>Continents</h2>
<ul>
{datas.map((data) => (
<li key={data.code}>{data.name}</li>
))}
</ul>
</>
);
}
export default Home;
@apollo/client
에서 제공하는 gql
이라는 template literal tag
를 사용해서 일반 자바스크립트 문자열을 GraphQL 구문으로 바꿔준다.useQuery
에 넘겨주면, apollo client가 graphql 서버로 graphql 쿼리를 요청하고 응답을 반환한다.optional chaining
을 사용하여 값이 null이 아닐 경우에만 조회하여 오류를 방지한다.이번엔 간단하게 데이터를 가져와서 나열하는 작업을 해보았다.
fetch작업을 통해 가져온 데이터의 상태관리에 있어서는,
그 데이터의 상태 관리를 위해 액션, 리듀서 등의 작성이 없이
바로 쿼리문을 통해 데이터를 받아오고 관리가 가능하다는 것이 흥미로웠다.
🚩 정정한 부분
이번 포스팅을 작성하게 된 계기는 apollo client
를 접하게 되고, redux
를 대체해서 사용할 수 있다는 글을 읽게 되어 공부를 하게 되었다.
그래서 처음엔 apollo client
가 상태관리로서의 역할을 한다고 생각을 했는데, 어떤 번역문을 읽으면서 제대로 된 이해를 하게 되었다.
내가 직접 redux
를 통해 상태관리를 했던 경험을 떠올리다보니, 대부분이
서버에서 가져온 데이터를 관리하는 것이었다.
그러다보니 이번 포스팅에서 말했던 것 처럼, graphQl
로 서버와 통신할 경우에 apollo client
를 사용하면 redux
를 사용하던 것 처럼 복잡한 작업(액션, 리듀서, 사가 등의 작성)이 많이 줄어들 수 있다는 것을 알게 되었다.
또한 서버에서 가져온 데이터를 apollo client
로 관리하면, UI를 위한 클라이언트의 상태관리 대부분은 react
의 상태관리 만으로도 가능해진다는 말을 이해하게 되었다.
물론 graphQl API
로 통신하기 위한 작업들이 필요하겠지만,
이번 포스팅을 작성하면서 apollo client
에 대한 개념을 이해하는 시간이었다 :)
참고하였습니다 :)
좋은 글 감사합니다.
약간의 사견을 덧붙이자면, 제가 번역한 "GraphQL은 어떻게 Redux를 대체하는가"는 서로 다른 레이어에서 동작하는 두개의 기술을 한 층위에서 "대체가능하다"고 다루는 부분이 다소 논쟁적인 글이라고 생각합니다. 다만 GraphQL(보다 정확히는 Apollo Client)의 Batch Call과 Client Cache를 사용하는 경우 대부분의 일반적인 어플리케이션 단위에서 사용되는 상태 관리가 대부분 대체될 수 있다는 점에 인사이트가 있다고 생각해요.
그래서 GraphQL이 Redux를 직접 대체한다- 보다는, Fetching + Client Cache를 동시에 사용하는 방식을 통해 서버 상태에 의존하는 영역의 React 상태관리를 대체할 수 있다가 더 정확한 표현이라고 생각합니다. 이러한 맥락에서 그 이후에 등장한 Fetching/Client Cache 솔루션들(SWR, React Query 등)과 비교해보시는 것도 좋은 스터디 주제가 되지 않을까 싶네요.
참고로, 개인적으로 저는 팀내에서 자체 개발한 E2E Type-safety 솔루션(a.k.a TypeFrame) 에 SWR(https://swr.vercel.app/ko)을 결합하는 방식으로 사용하고 있습니다. 여전히 모든 상태관리 솔루션들을 대체할 수는 없지만(클라이언트에만 필요한 데이터의 경우 Atom-based 방식의 Jotai를 사용합니다) 여기서 얻은 인사이트가 현재까지도 꽤 의미있는 기술 선택-활용의 주제가 되고 있네요.
graphql 은 fetching 을 하기 위한 query 이고
이 부분을 서버에서 받아주기 위해서 서버를 띄워야 하는데 그 부분을 연결해 주는 것이 apollo 인데
(서버에서 데이터를 가져오기위한 작업)
상태관리를 하는 redux와 비교가 될까요?