React Query

강준호·2024년 2월 7일

리액트

목록 보기
11/18

Redux vs React Query

propsdrilling => Redux => Recoil, contextAPI => Zustand /// ReactQuery( 결이 다름)

기존 Redux = 서버 DB에 수정해달라 하고, 리덕스 store 에 수정하고 해야함. 서버와 맞추면서 바꾸는게 너무 불편...ㅜ

=> 서버 DB와 동기화 시켜 주기 위해 React Query 를 사용.

정리

  • 모달창, 팝업창이 떠있는지 안떠있는지, 사용자가 어떤 페이지에서 뭐하는지 (클라이언트에서 관리하는거) => Redux , ContextAPI

  • 나머지 서버 사이드 => React Query


홈페이지가 어딘지 잘 모르겠어 => () 소괄호 사용해서 관리.


설치

npm i @tanstack/react-query

//dev tools
npm i @tanstack/react-query-devtools

사용방법?

1. Provider

  • QueryClientProvider를 최상단에서 감싸주고
  • QueryClient 인스턴스를 client props로 넣어 애플리케이션에 연결시켜야 한다.
"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";

const queryClient = new QueryClient();

export function ReactQueryProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <QueryClientProvider client={queryClient}>
      {children}
      <ReactQueryDevtools />
    </QueryClientProvider>
  );
}

useQuery

// 실제 예제

const getAllSuperHero = async () => {
  return await axios.get("http://localhost:4000/superheroes");
};

const { data, isLoading } = useQuery({
  queryKey: ["super-heroes"],
  queryFn: getAllSuperHero,
});
  • useQuery는 v5부터 인자로 단 하나의 객체만 받는다.
  • 그 중에 첫 번째 인자가 queryKey, queryFn가 필수 값이다.

쿼리키?

  • useQuery의 queryKey는 배열로 지정해줘야 한다.
  • useQuery는 queryKey를 기반으로 쿼리 캐싱을 관리하는 것이 핵심이다.
// An individual todo
useQuery({ queryKey: ['todo', 5], ... })

// An individual todo in a "preview" format
useQuery({ queryKey: ['todo', 5, { preview: true }], ...})

쿼리 Fn?

  • useQuery의 queryFn는 Promise를 반환하는 함수를 넣어야한다.
// (2) 상단의 queryKey 예제와 반대로 queryFn 자체적으로 인자를 받는 형태
const getSuperHero = async (heroId: string) => {
  return await axios.get(`http://localhost:4000/superheroes/${heroId}`);
};

const useSuperHeroData = (heroId: string) => {
  return useQuery({
    queryKey: ["super-hero", heroId],
    queryFn: () => getSuperHero(heroId), // (*)
  });
};

그 외 옵션들?

const useSuperHeroData = (heroId: string) => {
  return useQuery({
    queryKey: ["super-hero", heroId],
    queryFn: () => getSuperHero(heroId),
    gcTime: 5 * 60 * 1000, // 5분
    staleTime: 1 * 60 * 1000, // 1분
    retry: 1,
    // ... options
  });
};

useMutation

  • R(read)는 useQuery, CUD(Create, Update, Delete)는 useMutation을 사용한다.

  • 컴포넌트 레벨에서만 사용할 수 있어. (use... 등 훅 쓰는 자리에서.). 예를 들면, useEffect(), submit() 안에서 못씀

const mutation = useMutation({
  mutationFn: createTodo,
  onMutate() {
    /* ... */
  },
  onSuccess(data) {
    console.log(data);
  },
  onError(err) {
    console.log(err);
  },
  onSettled() {
    /* ... */
  },
});

const onCreateTodo = (e) => {
  e.preventDefault();
  mutate({ title });
};
  • use Mutation 은 mutationFn 만 받음

  • useMutation의 반환 값인 mutation 객체의 mutate 메서드를 이용해서 요청 함수를 호출할 수 있다.

  • mutate는 onSuccess, onError 메서드를 통해 성공 했을 시, 실패 했을 시 response 데이터를 핸들링할 수 있다.

  • onMutate는 mutation 함수가 실행되기 전에 실행되고, mutation 함수가 받을 동일한 변수가 전달된다.

  • onSettled는 try...catch...finally 구문의 finally처럼 요청이 성공하든 에러가 발생되든 상관없이 마지막에 실행된다.


뒤는 강의 정리

쿼리키를 작성하는 방법

  • 데이터를 구분하는 이름 => queryKey. 이건 유니크 해야해.
  • 배열로 작성해야해. 그 후에 안에 있는 값으로 구분해준다.
  • popular,latest 이런게 카테고리라고 정의하면,
  • 뒤 요소는 상관없이 배열에 첫번째 요소 키값으로만 다 날릴 수 있기때문에. 맨처음에 통일해서 쓸 수있는요소, 그 뒤에는 메타데이터를 넣어준다.
useQuery({ queryKey: ["til", { category: "latest" ,sort: "",}] });
  • useEffect 대신에 useQuery를 사용해.

1. useQuery(queryKey:[])

  • required 로 한개를 일단 만듬.(객체로 만들기 때문에 다양하게 가능).

  • 첫번째에는 queryKey: [] (배열로 쓴다)

  • 정체 identity가 될 명사를 적어놓는다. 두번쨰에는 다양한 정보를 적는다.

  • 사용된 쿼리에 대한 쿼리 키가 다 캐시에 정장돼

2. 쿼리 사용 useQuery(queryKey:[], queryFn:)

useQuery(queryKey:[],
queryFn : API.~~~}
);
  • 전역에서 여러개의 값을 관리하니까 쿼리 키가 필요해.

useQuery 안에 들어있는 것 중 중요한것들

  • data,
  • isLoading : true/false
  • refetch

  • 상세페이지 만들때는 대괄호로 디렉토리 만들어 => params 처럼

  • params는 항상 string

function TilDetailPage(props: {params: {tilId:string}})

useQuery({queryKey: ["til", {id:tilId}], queryFn: async () => {}})

  • 첫번째 인자는 요청했을때 응답

엑세스 토큰

  • JSON 웹 토큰은 디코드가 된다. 내용까면 다나와 => 암호화와 관련이 없음

  • iat: 언제 발급되었는지

  • sub: 아이디

  • name: 이름

핵심 기능

  • 위변조가 불가능!!

  • 서버에 보내지는 데이타 명은 dto 로.
  • "Bearer" : 여권의 종류(JWT) 명시하는 키워드
  • 로그인 할때 주고, 로그아웃할때 removeToken으로 여권 뺐어.

로그인 보장이 안될때

  useEffect(() => {
    if (isLoggedIn) {
      router.replace("/");
    }
  }, [router, isLoggedIn]);

이렇게 바뀐게 보장이 될때!

0개의 댓글