항해 취업 리부트 코스 6기 (사전스터디)-심화 3

Hunter Joe·2024년 11월 4일
0

항해99

목록 보기
6/7

TanStack Query 심화

  • 여기 있는 것들은 내가 직접 써보질 않아서 써볼 때 다시 세세하게 공부하고 지금은 이런게 있구나 하고 넘어가야겠다.

1. Query Cancellation

  • 다운로드 UI가 있을 때, 또는 UX를 저하시키는 불필요한 네트워크 요청을 제거하기 우위해 사용된다.
  • 대용량 fetching을 중간에 취소하거나, 사용하지 않는 컴포넌트에서 fetching이 진행중이면 자동으로 취소시켜 불필요한 네트워크 비용을 줄일 수 있다.
  • queryFn의 parameter로 Abort Signal을 받을 수 있고, 이를 통해 Query 취소가 가능하다.

참고(Abort Controller)

mdn - AbortController

TanStack Query - Query Cancellation

사용방법

queryFunctionContext

queryFn은 parameter로 queryFunctionContext이란 객체를 기본적으로 받는다.

export const getTodos = async (queryFnContext) => {
  const { queryKey, pageParam, signal, meta } = queryFnContext;
	// queryKey: 배열형태의 쿼리키
	// pageParam: useInfiniteQuery 사용 시 getNextPageParam 실행 시 적용
	// signal: AbortSignal 을 의미 (네트워크 요청을 중간에 중단시킬 수 있는 장치)
	// meta: query에 대한 정보를 추가적으로 메모를 남길 수 있는 string 필드

  const response = await axios.get("http://localhost:5000/todos", { signal });
  return response.data;
};

useQuery({
  queryKey: ["todos"],
  queryFn: getTodos,
})
// example: <div onClick={(event) => {}}

컴포넌트 unmount시 Query 취소

import axios from 'axios'

const query = useQuery({
  queryKey: ['todos'],
  queryFn: ({ signal }) => // queryFunctionContext의 signal 프로퍼티
    axios.get('/todos', {
      // Pass the signal to `axios`
      signal, // signal 설정
    }),
})

수동으로 Query 취소

주의사항

  • 대용량 fetching이 있는 경우 또는 Optimistic UI 를 구현할 때처럼 필요한 경우에만 적용할 것을 권장
  • 동영상 다운로드 같은 대용량 fetching이 아닌 이상 대부분의 GET 요청은 빠르게 완료 및 캐싱처리 됨

2. Optimistic Updates

TanStack Query - Optimistic Updates

  • 서버 요청이 정상적으로 잘 될거란 가정하에 UI 변경을 먼저하고, 서버 요청을 한다.
  • 서버 요청이 실패하는 경우, UI를 원상복귀(revert / roll back) 한다.

code

3. Prefetching

  • 페이지 이동 전에 이동할 페이지의 쿼리를 백그라운드에서 미리 호출(prefetching)한다.
  • 캐시 데이터가 있는 상태로 해당 페이지로 이동 시 로딩없이 바로 UI를 볼 수 있다.

4. Infinite Queries

  • 무한 스크롤 구현가능

주의

  • 서버에서 페이지들 별로 데이터를 제공하는 param을 제공해야 쓸 수 있음
import { useInfiniteQuery } from "@tanstack/react-query";
import { useInView } from "react-intersection-observer";
import { fetchMovieData } from "../api/movie";

export default function MovieInfiniteScroll() {
  const {
    data: movies,
    hasNextPage,
    fetchNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery({
    queryKey: ["movies"],
    queryFn: fetchMovieData,
    getNextPageParam: (lastPage) => {
      console.log("getNextPageParam 호출");
      console.log("lastPage: ", lastPage);
      if (lastPage.page < lastPage.total_pages) {
        console.log("다음 페이지로 pageParam 저장");
        return lastPage.page + 1;
      }
    },
    select: (data) => {
      return data.pages.map((pageData) => pageData.results).flat();
    },
  });
  
  console.log("hasNextPage:", hasNextPage);
  console.log("movies: ", movies);

  const { ref } = useInView({
    threshold: 1,
    onChange: (inView) => {
      if (!inView || !hasNextPage || isFetchingNextPage) return;
      fetchNextPage();
    },
  });

  return (
    <div>
      {console.log("무한스크롤 UI 렌더링")}
      <h1>영화 무한스크롤 예제</h1>

      <ul style={{ marginBottom: 300 }}>
        {movies?.map((movie) => (
          <li key={movie.id}>{movie.title}</li>
        ))}
      </ul>
      <div
        style={{
          textAlign: "center",
          backgroundColor: "green",
          color: "white",
          width: "100%",
          height: 50,
        }}
        ref={ref}
      >
        Trigger to Fetch Here
      </div>
    </div>
  );
}

실행 순서 (아우 어려워)

queryFn 실행
→ 캐시 데이터 등록 { pages, pageParam }
getNextPageParam 실행 (리턴된 NextPageParam는 훅 내부 메모리에 저장. 캐시에 저장X)
→ (NextPageParam 이 undefined이 아니면)hasNextPage true로 상태변경
fetchNextPage 실행
queryFn 실행 (이 때 내부적으로 저장되어 있던 NextPageParam을 queryFn 의 매개변수로 넘겨줌)

pages 와 pageParams를 갖는 캐시 데이터

  • useQuery 에서는 QueryFn 의 반환값이 캐시데이터로 등록됨
  • useInfiniteQuery 에서는 QueryFn 의 반환값은 pages 배열의 요소로 추가되고, 매개변수로 받았던 pageParam은 pageParams 배열의 요소로 추가됨

useInfiniteQuery 사용 시 주의 사항

  • 훅 내부적인 동작원리로 인해 예상보다 잦은 리렌더링이 발생할 수 있다.
  • 연산량이 많은 코드가 있는 경우 useMemo 와 같은 memoization 적용을 특히 고려해야 합니다.
  • 리렌더링이 발생한다고 해서 실제 브라우저 렌더링이 발생하는 것은 아님(Virtual DOM 원리 이해 필요)

참고

profile
두 or 다이 / FE 목표
post-custom-banner

0개의 댓글