📝

무한 스크롤 구현하기(Apollo-graphQL Client )

Created
2023/03/10 05:47
Tags
안녕하세요. 볼드나인 프론트엔드 개발자 장예지입니다.
이 글에서는 Apollo GraphQL client를 이용한 무한 스크롤 구현에 대해서 알아보겠습니다.
Apollo GraphQL client는 React 애플리케이션에서 GraphQL API를 쉽게 사용할 수 있게 해주는 도구입니다.
이를 이용하면 서버로부터 데이터를 받아와 컴포넌트에서 렌더링 하는 것이 간편해집니다.

 무한 스크롤을 사용하는 이유?

무한 스크롤 기능은 사용자 경험을 향상시키는 중요한 요소 중 하나입니다.
일반적으로 블로그나 웹사이트에서는 ‘다음’ 버튼을 눌러야 페이지를 불러오는 방식을 이용합니다.
그러나 이러한 방식은 사용자가 페이지를 불러올 때마다 매번 새로고침이 발생하고,
페이지 로딩 시간이 오래 걸릴 수 있다는 단점이 있습니다.
반면 무한 스크롤은 사용자가 페이지를 자연스럽게 스크롤 하는 과정에서
새로운 컨텐츠를 자동으로 로딩해 줌으로써 이러한 불편함을 해소할 수 있습니다.
또한 서버로부터 필요한 데이터만을 요청하고 받아올 수 있으므로, 불필요한 데이터 로딩을 줄일 수 있습니다.
이를 통해 빠른 페이지 로딩과 높은 성능을 보장할 수 있습니다.

무한 스크롤 구현하기 전 알아두면 유용한 Apollo-graphQL 기본 개념

1. cursor pagiantion

Cursor pagination은 이전 페이지에서 마지막으로 로드된 아이템을 기준으로 다음 페이지를 로드하는 방식입니다. 이전 페이지에서 마지막으로 로드된 아이템의 고유 식별자를 사용하여 다음 페이지를 가져옵니다.
예를 들어, 1000개의 결과가 있는 데이터베이스 쿼리를 실행하고, 페이지당 50개의 결과를 보여주고 싶다면,
첫 페이지에서는 처음 50개의 결과를 로드하고 마지막 결과의 cursor를 저장합니다.
두 번째 페이지에서는 이전 페이지에서 저장한 cursor를 사용하여 쿼리를 실행하고,
다음 50개의 결과를 로드합니다. 이 과정을 반복하여 모든 페이지를 가져올 수 있습니다.
Cursor pagination은 페이지 간 이동이 빠르고 쉽고, 페이지 수가 많은 데이터를 처리하는 데 효율적입니다.

2. fetch policy

Apollo GraphQL에서는 데이터를 가져오는 방식을 지정할 수 있는 fetch policy 옵션을 제공합니다.
이 옵션은 쿼리를 실행할 때 Apollo가 어떤 데이터를 가져와야 하는지 결정하는 데 사용됩니다.
1.
cache-first: Apollo는 쿼리에 대한 데이터를 먼저 캐시에서 찾습니다. 캐시에 데이터가 없으면 서버로 요청하여 데이터를 가져옵니다. 이후에도 데이터가 변경되지 않는 한 캐시 된 데이터를 사용합니다.
2.
cache-and-network: Apollo는 캐시에서 데이터를 찾고, 동시에 서버로도 데이터를 요청합니다. 서버로부터 데이터가 반환되면 캐시 된 데이터와 함께 업데이트합니다. 캐시 된 데이터는 즉시 사용할 수 있습니다. 실시간으로 변경이 잦은 데이터의 빠른 응답 속도를 위해 캐시 데이터를 먼저 반환하고 이후에 서버에서 받아온 데이터를 응답할 때 유용합니다.
3.
network-only: Apollo는 서버에서 데이터를 가져옵니다. 캐시에 저장하지 않습니다.
4.
cache-only: Apollo는 캐시에서만 데이터를 가져옵니다. 캐시에 데이터가 없으면 null을 반환합니다.
5.
no-cache: Apollo는 캐시에서 데이터를 사용하지 않고, 서버에서 데이터를 가져옵니다. 서버에서 가져온 데이터는 캐시 되지 않습니다.

 Apollo-graphQL Client 이용하여 무한스크롤 구현하기

1. Step

1.
초기 데이터 로딩 페이지가 처음 로드될 때 초기 데이터를 쿼리 합니다. 이 쿼리에서는 무한 스크롤의 첫 번째 페이지에 필요한 데이터를 가져옵니다. 이 데이터는 화면에 표시되고, 스크롤이 끝까지 이동할 때 새로운 데이터를 가져오는데 사용됩니다.
2.
다음 페이지 데이터 가져오기 스크롤이 끝까지 이동하면 클라이언트에서는 다음 페이지에 필요한 데이터를 쿼리 합니다. 이때 이전 페이지에서 가져온 데이터를 사용하여 쿼리를 작성하고, 다음 페이지의 데이터를 가져옵니다.
3.
새로운 데이터 추가 클라이언트에서 다음 페이지의 데이터를 가져온 후, 이를 화면에 추가합니다. 이를 위해 일반적으로 렌더링 된 목록의 끝에 새로운 아이템을 추가합니다.
4.
반복 이러한 단계를 반복하여 스크롤이 끝까지 이동할 때마다 새로운 페이지의 데이터를 가져와 화면에 추가합니다. 이를 통해 무한 스크롤 기능을 구현할 수 있습니다.

2. 구현 예시

1. GraphQL 쿼리에서 cursor 및 limit 인자를 사용하여 첫 페이지를 가져옵니다.
query GetItems($limit: Int!, $cursor: String) { items(first: $limit, after: $cursor) { edges { cursor node { id name # 추가 필드 } } pageInfo { hasNextPage endCursor } } }
GraphQL
복사
2. Apollo Client에서 useQuery hook을 사용하여 첫 페이지를 가져옵니다.
import { useQuery } from '@apollo/client'; const [cursor, setCursor] = useState<string>(''); const { loading, data} = useQuery(GET_ITEMS_QUERY, { variables: { input: { cursor: cursor, limit: 15, //가져올 데이터의 양을 지정 }, }, fetchPolicy: 'cache-and-network', // 데이터 가져오는 방식 지정 });
TypeScript
복사
3.
scroll이 하단부에 도달했을 때 발생하는 동작을 설정해 줍니다.
const handleScroll = useCallback(() => { const lastCursorId = data[data?.length - 1]?.id ?? null; const isBottom = document.documentElement.scrollTop + window.innerHeight > document.documentElement.offsetHeight; // 화면 하단여부 확인 if (isBottom && data?.length && !loading) { setCursor(lastCursorId); //마지막 데이터의 id를 가져와서 cursor를 업데이트 시켜서 새로운 데이터를 받아 } }, [data, loading]);
TypeScript
복사
4.
무한 스크롤이 필요한 부분에 스크롤 이벤트를 설정합니다.
<Box onScroll={handleScroll} > {items?.length ? ( <List> {items.map((v) => ( <ListItem key={v.id}></ListItem> ))} </List> </Box>
TypeScript
복사

마무리

이상으로 Apollo GraphQL client를 이용한 무한 스크롤 구현에 대한 간략한 소개였습니다.
이를 통해 매끄러운 사용자 경험과 더 나은 성능을 제공하는 무한 스크롤을 구현할 수 있었습니다.
더 자세한 정보는 공식문서 Apollo 에서 확인 가능합니다.
감사합니다.