Skip to main content

Command Palette

Search for a command to run...

[React] Tanstack-Query에 대해서 알아보자 & 무한스크롤 구현

Updated
5 min readView as Markdown
[React] Tanstack-Query에 대해서 알아보자 & 무한스크롤 구현

최근에 인프런 멘토링을 받았는데 tanstack-query는 프론트엔드 개발자에게 선택이 아닌 필수다! 라는 이야기를 듣고 이번 프로젝트에 직접 사용해보려고 한다.

일단 사용하기에 앞서 공부한 내용을 정리하려고 한다 ! 🌱

(평소에는 공부한 내용들을 깃허브에 기록하지만 내가 작성한 내용이 누군가에게 도움이 되면 좋겠는 마음에 …. ✨)

굉장히 많은 도움을 받은 블로그입니다,,👍🏻

✨ Tanstack-Query(react-query)가 뭔가요 ?

  • Tanstack-Query는 서버로부터 데이터 가져오기 + 데이터 캐싱 + 캐시 제어 등 데이터를 쉽고 효율적으로 관리할 수 있는 라이브러리이다.

쉽게 설명하자면

  1. 서버 데이터 가져오기(fetching)

보통 웹앱에서 API 서버에 요청해서 데이터를 받아와야 하는데 (ex. 게시글 목록, 사용자 정보, 댓글)

  • TanStack Query를 사용하면 API 호출하는 코드를 간단하게 작성할 수 있다

  • 내부적으로 데이터 요청 시 상태(로딩중, 성공, 실패)도 자동으로 관리해준다

  1. 데이터 캐싱(caching)
  • 서버에서 받은 데이터는 자동으로 캐시에 저장된다

  • 그래서 같은 데이터를 또 요청할 때, 이미 캐시에 있으면 서버에 다시 요청하지 않고 캐시 데이터를 바로 보여준다

  • 덕분에 사용자 경험이 훨씬 빨라지고 서버 부담도 줄어서 완전 최고 !

⁉️ 여기서 캐싱이 뭐지

→ 캐싱은 자주 쓰는 데이터를 미리 저장해 두었다가 빠르게 꺼내 쓰는 기술이다

실제 웹에서의 캐시

웹 앱에서는 데이터를 서버(API)에서 불러오는데 시간이 걸린다
예를 들어 게시판 글을 불러오면

  • 네트워크 요청 → 서버 처리 → 응답 받기 → 렌더링

  • 이 과정은 1초 이상 걸릴 수도 있음

하지만 TanStack-Query 같은 라이브러리가 그 데이터를 메모리에 저장(=캐싱) 해두면

  • 같은 데이터를 다시 보여줄 때 서버에 다시 안 물어보고 즉시 보여줄 수 있고

  • 사용자는 훨씬 빠르게 화면을 보게 되고 서버 부담도 줄어든다

  1. 캐시 자동 갱신
  • 캐시된 데이터가 너무 오래되면 자동으로 서버에서 최신 데이터를 다시 받아와 갱신한다

  • 사용자가 뭔가 조작해서 데이터가 바뀌면 자동으로 최신 상태를 유지하도록 업데이트도 해준다

  1. 데이터 상태 관리 간소화
  • 로딩중, 에러, 성공 상태를 별도로 useState, useEffect로 관리할 필요가 거의 없다

  • TanStack Query가 알아서 상태 관리해주니까 개발자가 집중할 부분이 줄어든다

  1. 캐시 제어 및 동기화
  • 개발자가 필요하면 언제든 캐시를 수동으로 갱신하거나 삭제할 수 있다

  • 여러 컴포넌트에서 같은 데이터를 공유할 때 자동으로 동기화시켜준다

Tanstack-Query에 중요한 개념

  • staleTime(default:0)

    1. 데이터를 신선하다고 간주하는 시간이다.

    2. 이 시간이 지나기 전까지는 React Query는 데이터를 **“신선함”**으로 간주하고 자동으로 재요청을 하지 않는다

    3. 예를 들어 staleTime: 5000으로 설정하면 데이터를 가져온 후 5초 동안은 재요청 없이 기존 데이터를 사용한다

useQuery(['todos'], fetchTodos, {
  staleTime: 5000, // 5초 동안은 데이터를 fresh하게 유지
});
  • cacheTime (기본값: 5분)

    1. 쿼리가 언마운트된(=컴포넌트가 화면에서 사라지는 것) 후에도 메모리에 데이터를 유지하는 시간이다.

    2. 이 시간이 지나면 쿼리 데이터는 가비지 컬렉션처럼 삭제된다

    3. 예를 들어 cacheTime: 10000이면, 컴포넌트가 언마운트된 후에도 쿼리 데이터는 10초간 캐시에 유지된다. 그 안에 같은 쿼리가 다시 마운트되면, 기존 데이터로 빠르게 로드된다.

useQuery(['todos'], fetchTodos, {
  cacheTime: 10000, // 쿼리 언마운트 후 10초 동안 캐시 유지
});

구분되어야 하는 점

Zustand와 같은 상태관리 라이브러리는 클라이언트의 데이터를 관리하는 것이고 Tanstack-Query의 경우에는 서버 데이터를 관리하는 것이라서 사용목적이 다르다✍🏻

사용예시

Zustand

✅ 다크모드 on/off
✅ 드롭다운 열기/닫기
✅ 로컬 폼 입력 값

Tanstack-Query

✅ 게시글 목록 가져오기
✅ 댓글 불러오기
✅ 서버 상태 실시간 유지

📚 대표적으로 자주 사용되는 기능들

기술/개념설명
useQuery데이터를 불러올 때 사용하는 훅. 서버에서 데이터 조회 (GET).
useMutation데이터를 변경(쓰기) 할 때 사용. POST, PUT, PATCH, DELETE 등에 사용.
queryKey쿼리의 고유한 키. 캐싱, 리패치 기준이 되는 중요한 요소. 예: ['posts', postId]
queryFn데이터를 가져오는 함수. 보통 axios, fetch 등으로 API 요청을 보냄.
staleTime데이터를 fresh로 간주하는 시간. 이 시간 내엔 자동 리패치 안 함.
cacheTime컴포넌트가 언마운트된 뒤 캐시를 메모리에 유지하는 시간.
refetch데이터를 수동으로 다시 불러오는 함수. const { refetch } = useQuery(...)
onSuccess, onError쿼리나 뮤테이션이 성공 또는 실패했을 때 실행할 콜백 함수.
enabled조건이 true일 때만 쿼리를 실행. 조건부 쿼리에 사용됨.
select쿼리 결과를 가공해서 리턴하는 함수. 데이터를 정제하거나 일부만 추출할 때 유용.
invalidateQueries특정 쿼리를 무효화하여 다시 refetch하게 만드는 기능. (queryClient.invalidateQueries)
setQueryData쿼리 캐시의 데이터를 직접 업데이트. optimistic UI 구현 등에 사용.

실제 사용 예시

이번 프로젝트에서 무한스크롤을 Tanstack-Query를 사용해서 구현해봤다.

Tanstack-QueryuseInfiniteQuery, getPreviousPageParam, fetchPreviousPage, hasPreviousPage 등과 같은 페이지 관련 기능이 존재해 이를 이용해 무한 스크롤을 쉽게 구현할 수 있었다..!!

import { useInfiniteQuery } from '@tanstack/react-query'
import InfiniteScrollList from '../../../../components/common/InfiniteScrollList'

  const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } = useInfiniteQuery({
    queryKey: ['relatedPosts', currentId], //쿼리 고유 키
    queryFn: async ({ pageParam = null }) => {
      const { boards } = await getAllPosts({ last: pageParam, size: 6 }) //API 요청 
      return boards.filter((p) => String(p.boardId) !== String(currentId)) //현재 게시글 제외
    },
    getNextPageParam: (lastPage) => {
      const lastItem = lastPage[lastPage.length - 1]
      return lastItem?.boardId ?? undefined
    },
    enabled: !!currentId,
  })

  const posts = data?.pages.flat() || []
  //data.pages는 2차원 배열이므로 flat()으로 하나의 배열로 합침
  return (
    <InfiniteScrollList
      onIntersect={() => fetchNextPage()}
      disabled={!hasNextPage || isFetchingNextPage}
    >

    </InfiniteScrollList>
  )
}

export default RelatedPosts
  • useInfiniteQuery: React Query의 훅. 무한 스크롤용 쿼리를 설정한다

  • queryKey: 쿼리를 구별하는 고유 키 (캐싱에 사용됨)

  • queryFn: 서버에서 데이터를 가져오는 함수 (getAllPosts)

  • getNextPageParam: 다음 페이지 요청에 필요한 값을 설정 (여기선 마지막 게시글의 boardId)

  • enabled: 조건이 true일 때만 쿼리를 실행 (여기선 currentId가 존재할 때)

이런식으로 사용해줬다.

지금 구인 쪽은 fresh 상태로 뜨고 있는 것을 확인할 수 있다..✨

🌱 배운점

  • 리액트 쿼리에 대한 궁금증은 가득했지만 실제로 적용해보고 공부해본 적이 이번이 처음인데, 굉장히 유용한 기능이다 🥳
    특히 서버에서 데이터를 가져오고 관리하는 과정이 자동화되어 불필요한 로딩 상태 관리나 캐시 처리 코드가 줄어든다는 점이 인상적이었다.

  • 무한 스크롤 구현도 useInfiniteQuery 하나로 깔끔하게 해결할 수 있었고 queryKey를 통해 데이터를 구분하고 캐싱하는 방식도 굉장히 체계적이라 느꼈다. 처음에는 다소 어렵게 느껴졌지만 개념 하나하나를 이해하고 나니 React Query는 서버 데이터 관리의 필수 도구라는 확신이 생겼다.

  • 앞으로도 더 복잡한 기능(invalidateQueries, onSuccess, refetch) 등을 직접 활용하면서 계속 익혀보고 싶다! 💪

More from this blog

[회고] 풀스택 개발자로 (곧) 1년...

정말 정말 오랜만에 글을 작성한다 🤭 나는 현재 개발자로 취업한 지 거의 1년이 다 되어간다. 이제 10개월임 ! 처음에는 무조건 프론트엔드 개발자로 취업할거임!! 풀스택 NO ! 라는 마음으로 준비했던 취업.. 하지만 현실은 풀스택으로 취업하게 되었다. 취업을 하고 나니 여러가지 생각과 감정이 들었고 맨날 회고 적어야지 ~ 적어야지 ~ 했는데 10개

May 29, 20263 min read

[React] 클라이언트에서 이미지를 압축해보자

우리는 서버 비용을 직접 부담하고 있기 때문에 항상 최적화와 비용 절감 방법을 고민하게 된다. 현재 자유게시판이 활성화가 많이 되지는 않았지만 사용자들이 업로드하는 이미지가 평균 5MB 이상일 경우를 대비해서 클라이언트에서 이미지 압축을 진행했다. 웹에서는 크게 두 가지 방법이 있었는데 Canvas API를 직접 사용하는 방법 browser-image-compression 라이브러리를 활용하는 방법 이 있다. 여러 장점을 고려해 brow...

Oct 8, 20252 min read
[React] 클라이언트에서 이미지를 압축해보자

[책 추천] 프론트엔드 개발자라면 반드시 알아야 할 '웹 접근성' 이야기

내가 생각하는 프론트엔드 개발자는 단순히 보이는 화면만 구현하는 것을 넘어서 누구나 접근할 수 있는 웹을 만드는 데 중요한 역할을 해야 한다고 생각한다. 실무에 바로 적용하는 웹 접근성 가이드북 이번에 이 책을 받고 프엔들이 읽기에 너무 좋다고 생각해서 블로그에 추천 글까지 적게 되었다 ! 목차 Chatper1. 쉽게 이해하는 접근성 Chapter2. 웹 접근성의 기초 Chapter3. HTML 태그, 의미 있게 사용하기 Chpater4...

Jul 27, 20255 min read
[책 추천] 프론트엔드 개발자라면 반드시 알아야 할 '웹 접근성' 이야기

[Next.js] 나만의 학습 블로그 만들기#3-다국어 지원 (Feat.next-i18next)

오늘은 다국어 지원 가능한 기능 구현 과정을 적어보려고 한다. 원래는 댓글기능보다 먼저 구현하려고 했는데 ,, 갑자기 댓글기능 알아보다가 재밌어서 먼저 끝내버렸다,,,🙄 시작하기 전에 정말 어려웠다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 어려움이 많아서 기능 적용하는 데 시간이 꽤 걸렸다 ,,, 다국어 지원 기능 나는 영어랑 일본어를 추가해줬다 ! (해외취업도 관심 있기 때문에 나중에 이력서 낼 때 도움이 되지 않을까? ..🤭) 다국어 구현 방법 구현 방...

Jul 15, 20254 min read
[Next.js] 나만의 학습 블로그 만들기#3-다국어 지원 (Feat.next-i18next)

[Next.js] 나만의 학습 블로그 만들기#4 - 댓글 기능(Feat. Giscus)

댓글기능이 있으면 무조건 재밌을 거 같아서 넣어보려고 한다🤭 아무래도 개발에 관련된 학습 블로그라서 개발자들이 많을 것으로 예상했다 ! 그래서 깃허브 이슈 기반 댓글 시스템을 기반으로 기능을 구현해보려고 한다. 👉🏻 도움이 많이 된 블로그 ! 방법 Giscus | (https://giscus.app) utterances | (https://utteranc.es) 알아봤을 때는 이렇게 두 개가 유명하다고 한다. 그럼 각각의 특징과 장...

Jul 14, 20253 min read
[Next.js] 나만의 학습 블로그 만들기#4 - 댓글 기능(Feat. Giscus)
S

subin-dev-blog

28 posts

끊임없이 배우기 위해 노력합니다. 🌱