🌸 React Query

이도경·2023λ…„ 3μ›” 29일
0

fRONTeND

λͺ©λ‘ 보기
8/14
post-thumbnail

ν”„λ‘ νŠΈμ—”λ“œλ₯Ό κ°œλ°œν•˜λ‹€λ³΄λ©΄ κ΅¬ν˜„μ€ κ°„λ‹¨ν•˜μ§€λ§Œ 번거둜운 μž‘μ—…λ“€μ΄ λͺ‡λͺ‡ μžˆμŠ΅λ‹ˆλ‹€. 캐싱, 패치, μ—…λ°μ΄νŠΈ, API 톡신, λ‘œλ”©, λ¬΄ν•œμŠ€ν¬λ‘€ λ“±λ“±λ“±... 이런 개발자의 수고λ₯Ό λœμ–΄μ£ΌλŠ” 라이브러리 React Queryλ₯Ό μ†Œκ°œν•©λ‹ˆλ‹€. 이번 ν¬μŠ€νŠΈμ—μ„œ λŒ€ν‘œμ μΈ κΈ°λŠ₯ λͺ‡ 가지λ₯Ό μž‘μ„±ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

React Qurey 🌸

useQuery()

RQ의 κ°€μž₯ λŒ€ν‘œμ μΈ κΈ°λŠ₯ uesQuery λŠ” 비동기 λ‘œμ§μ—μ„œ μž‘λ™ν•˜λ„λ‘ μ„€κ³„λ˜μ—ˆκ³ , api 톡신 쀑 Promise λ₯Ό ν†΅ν•œ GET 의 μ„œλ²„μ—μ„œ 데이터λ₯Ό κ°€μ Έμ˜¬ λ•Œ 유용히 μ‚¬μš©λ©λ‹ˆλ‹€.

How?

useQuery()의 기본적인 μ‚¬μš©λ²•μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

result = uesQuery(μœ λ‹ˆν¬ 인덱슀, ν•¨μˆ˜);

  const result = useQuery('todos', getTodos);

λ³€μˆ˜ resultμ—λŠ” λ‹€μŒκ³Ό 같은 값이 ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

  • isLoadingλ˜λŠ” status === 'loading'- 쿼리에 데이터가 μ—†μœΌλ©° κ°€μ Έμ˜€λŠ” 쀑
  • isError λ˜λŠ” status === 'error'- 쿼리에 였λ₯˜ 방생
  • isSuccess λ˜λŠ” status === 'success'- 쿼리λ₯Ό μ„±κ³΅ν•˜μ—¬ 데이터 μ‚¬μš©κ°€λŠ₯
  • isIdle λ˜λŠ” status === 'idle'- ν˜„μž¬μ˜ 쿼리가 λΉ„ν™œμ„±ν™”

Ref

이λ₯Ό ν†΅ν•œ 일반적인 μ‚¬μš©λ²•μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

function Todos() {
  const { isLoading, isError, data, error } = useQuery('todos', fetchTodoList)

  if (isLoading) {
    return <span>Loading...</span>
  }

  if (isError) {
    return <span>Error: {error.message}</span>
  }

  // `isSuccess === true` 라고 κ°€μ •ν•  수 있음.
  return (
    <ul>
      {data.map(todo => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}

μœ„μ˜ μ˜ˆμ œλŠ” κ³΅μ‹λ¬Έμ„œμ˜ κ°„λ‹¨ν•œ todo μ˜ˆμ œμž…λ‹ˆλ‹€. μ‹€μ œ μ˜ˆμ œμ—μ„œ μ–΄λ–»κ²Œ μ‚¬μš©ν–ˆλŠ”μ§€ ν™•μΈν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

//data: [λΆ€λ₯Ό 이름], ... 
//useQuery 등을 μ€‘λ³΅μœΌλ‘œ μ‚¬μš©ν•  수 μžˆκΈ°μ— 각 ν•¨μˆ˜λ³„λ‘œ 이름을 μ„ μ–Έν•©λ‹ˆλ‹€.
  const { data: geoData, isSuccess: geoSuccess } = useQuery(
    "detail/getRevGeo",
    // μ‹€ν–‰ν•  μ½”λ“œ, (μ•„λ§ˆλ„ μ’Œν‘œκ°’μ„ μ „μ†‘ν•˜μ—¬ 행정상 지역이름을 λ¦¬ν„΄ν•˜λŠ” μ½”λ“œ)
      GetRevGeocode({ lat: postData?.latitude!, lng: postData?.longitude! }),
    {
	  //qurey option μœ„μΉ˜, 정말 μˆ˜λ„μ—†μ΄ λ§Žμ•„μ„œ λ”°λ‘œ 링크 λ‚¨κΈ°κ² μŠ΅λ‹ˆλ‹€.
	  //μž¬μ‹œλ„ 횟수 μ„ μ–Έ
      retry: 1,
    }
  );
    
    const { status, data } = useQuery(
    ['quizDetail'],
    () => getQuizDetail(quizId),
    {
      onSuccess: (res) => {
	    // μ–΄λ–€ λ™μž‘λ“€
      },
      onError: () => {
        toast.error('μ•Œ 수 μ—†λŠ” 였λ₯˜κ°€ λ°œμƒν•˜μ˜€μŠ΅λ‹ˆλ‹€.');
      },
    }
  );

useQuery

useInfiniteQuery()

ν•œλ²ˆμ€ λ¬΄ν•œ μŠ€ν¬λ‘€μ„ κ΅¬ν˜„ν•΄λ³Έ κ²½ν—˜μ΄ μžˆμŠ΅λ‹ˆλ‹€. 정말 λ§Žμ€ μ˜€ν”ˆμ†ŒμŠ€μ™€ 라이브러리, λΈ”λ‘œκ·Έ 등을 μ°Ύμ•„ 겨우겨우 μ™„μ„±ν–ˆλ˜ 기얡이 λ‚˜λ„€μš”. RQμ—μ„œλŠ” 제 κ³Όκ±° κ²½ν—˜μ΄ 무색할 μ •λ„λ‘œ μ•„μ£Ό κ°„λ‹¨ν•˜κ²Œ λ¬΄ν•œ μŠ€ν¬λ‘€μ„ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
기본적으둜 νŽ˜μ΄μ§€ λ‹¨μœ„λ‘œ νŠΉμ • λ‹¨μœ„ index λ§ˆλ‹€ fetchλ₯Ό μ‹€ν–‰ν•˜κ³  hasNextPage, fetchNextPage() λ“±μœΌλ‘œ νŽ˜μ΄μ§•μ„ 관리할 수 μžˆμŠ΅λ‹ˆλ‹€.

useInfiniteQuery 도 useQuery와 μœ μ‚¬ν•©λ‹ˆλ‹€. λͺ‡λͺ‡ μš”μ†Œλ“€μ΄ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

How

result = useInfiniteQuery(μœ λ‹ˆν¬ 인덱슀, ν•¨μˆ˜);

Ref

쑰금 μ§€μ €λΆ„ν•˜μ§€λ§Œ μ°Έκ³ κ°€ 될까봐, λΆ€λ„λŸ¬μš΄ μ½”λ“œλ₯Ό μ²¨λΆ€ν•©λ‹ˆλ‹€. πŸ₯²

const {
    data: myData,
    isFetching: myIsFetching,
    isSuccess: myIsSuccess,
  	// λ‹€μŒ νŽ˜μ΄μ§€λ₯Ό 뢈러올 
    fetchNextPage: myfetchNextPage,
    hasNextPage: myHasNextPage,
  } = useInfiniteQuery(
    ["mypage/mypost"],
    ({ pageParam = 0 }) => GetPostMine({ idx: pageParam }),
    {
      retry: 3,
      getNextPageParam: (lastPage, allPages) => {
        if (
          //제 ν™˜κ²½μ—μ„œμ˜ 쑰건 (개인 ν™˜κ²½μ— 맞게 μˆ˜μ •)
          lastPage[lastPage.length - 1]?.statusCode === 500 ||
          allPages.flat().length !== 15
        )
          return null;
        return Math.floor((1 + allPages.flat().length) / 15);
      },
      onSuccess(data) {
        console.log(data);
      },
    }
  );

useInfiniteQuery()의 λ‘œμ§μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ–΄λ–€ μƒν™©μ—μ„œ ν•¨μˆ˜κ°€ μ‹€ν–‰λ˜μ•Ό ν•˜λŠ”μ§€ κΆκΈˆν•˜μ‹€κ²ƒ κ°™μ•„ μΆ”κ°€ν•©λ‹ˆλ‹€.

νŠΉμ • DOM 객체λ₯Ό ref둜 μ§€μ •ν•©λ‹ˆλ‹€.

const [ref, inView] = useInView();

μ§€μ •ν•œ refκ°€ μ‚¬μš©μžμ˜ λΈŒλΌμš°μ €μ— λ³΄μ΄κ±°λ‚˜ λ‹€μŒ νŽ˜μ΄μ§€κ°€ 있으면 myfetchNextPage()λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.

useEffect(() => {
  if (inView && myHasNextPage) myfetchNextPage();
});

μ‚¬μš©λœ ref DOM 객체

<div style={{ width: "100vw", height: "5rem" }} ref={ref}></div>

useInfiniteQuery

useMutation()

GET을 μ‚¬μš©ν•˜μ—¬ λ‹¨μˆœνžˆ 쑰회λ₯Ό ν•˜λŠ” useQuery와 달리 데이터λ₯Ό POST, PUT, DELETEλ₯Ό μ‚¬μš©ν•˜λŠ” λ“± ( 생성, μ—…λ°μ΄νŠΈ, μ‚­μ œ ) μ„œλ²„λ‘œλΆ€ν„° 데이버 λ³€κ²½ μš”μ²­λ“€μ€ mutatation을 μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

How

mutation = useMutation(ν•¨μˆ˜, {opt});

Ref

//putPost: μˆ˜μ •μ„ λ‹¨λ…μ μœΌλ‘œ μˆ˜ν–‰ν•˜λŠ” ν•¨μˆ˜
const { mutate } = useMutation(PutPost, {
    onMutate: (data) => {
      //μ‹œμž‘ μ‹œ
      setSubmitLoding(true);
    },
    onError: (error: Error) => {
      setError(error.message);
    },
    onSettled: () => {
      //μ’…λ£Œ μ‹œ
      setSubmitLoding(false);
    },
  });

useMutation

useQuery λ“±κ³Ό λ™μΌν•˜μ§€λ§Œmutation.* 으둜 .mute, .isLoading ... λ“±μœΌλ‘œ μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Options

react queryμ—λŠ” 정말 λ‹€μ–‘ν•œ κΈ°λŠ₯의 μ˜΅μ…˜λ“€μ΄ μžˆμŠ΅λ‹ˆλ‹€.

retry 둜 refetch 섀정을 μ„ΈνŒ…ν•  수 있고, enabled λ₯Ό 톡해 쑰건뢀 싀행을 ν•  수 μžˆλŠ” λ“± μœ μš©ν•œ κΈ°λŠ₯듀이 많이 μžˆμŠ΅λ‹ˆλ‹€.

profile
μ•ˆλ…•ν•˜μ„Έμš©

0개의 λŒ“κΈ€