React

[데이터패치] ReactQuery 및 SWR을 사용하는 이유는?

썽연 2022. 7. 26. 13:51
728x90

서버 상태관리를 하는 대표적인 두가지 라이브러리는 RactQuery와 SWR이 있다.

즉, 두 라이브러리 모두 data fetch를 도와주는 라이브러리이다.

사용하는 이유가 무엇일까?

  • 어떤 데이터를 언제 fetch하면 되는지 목표만 기술하면 된다.
  • 동일한 API 요청이 여러 번 호출될 경우 한 번만 실행
  • 자연스럽게 흐름 파악 가능

SWR

import useSWR from "swr";

function Profile() {
  const { data, error } = useSWR("/api/user", fetcher, options);

  if (error) return <div>failed to load</div>;
  if (!data) return <div>loading...</div>;
  return <div>hello {data.name}!</div>;
}

data와 error 명시

첫 번째 인자는 key값이며 두 번째 인자는 fetcher함수이다.

fetcher함수의 key값이 첫 번째 파라미터로 전달된다.

promise를 리턴하는 모든 함수가 올 수 있어, 기본 fetch함수 뿐만 아니라, axios 등과 같은 별도 라이브러리가 사용가능하다.

세번째 파라미터는 options로, 사용자가 페이지를 탐색 중 다른 탭을 보다가 다시 돌아왔을 때 네트워크가 끊어졌다가 다시 연결되었을 때 refetch할 수 있도록 옵션을 설정할 수 있다.

React Query

import { useQuery } from "react-query";

const useUser = id => {
  const result = useQuery(`/user/${id}`, fetcher, options);

  return result;
};

function Example() {
  const { isLoading, error, data } = useUser("123");

  if (isLoading) return "Loading...";
  if (error) return "An error has occurred: " + error.message;
  return <div>hello {data.name}!</div>;
}

SWR과 비슷한 사용방법으로,

첫 번째 인자는 unique한 key값으로 url이나 unique한 값 (string, array)이라면 뭐든지 가능하다.

key를 배열로 사용할 때 주의할 점 object가 포함되었을 경우 object는 항목들이 동일하다면(키 값이 같으면?) 명시 순서가 다르더라도 동일한 key를 취급하지만, array를 키로 설정할경우 순서가 다르면 다른 키로 취급된다.

두 번째 인자는 fetcher함수이다. promise를 리턴하는 모든 함수가 올 수 있으며, fetch 함수 뿐만 아니라, axios도 가능하다.

data fetching 라이브러리를 사용하면, 데이터를 쉽게 가져올 수 있고, 동일한 요청을 하는 여러 컴포넌트가 동시에 렌더링 되더라도 한 번만 요청한다.

백그라운드에서 서버에 주기적으로 polling을 하면서 데이터가 유효한지 검사하고, 유효하지 않으면 업데이트하여 데이터를 동기화한다.

state에 따라 api요청을 막고싶은 경우는?

SWR

// state에 따라 key 값을 null로 만들면 fetch가 실행되지 않습니다.
const { data } = useSWR(shouldFetch ? "/api/data" : null, fetcher);

// key 함수가 falsy 값을 리턴하면 fetch가 실행되지 않습니다.
const { data } = useSWR(() => (shouldFetch ? "/api/data" : null), fetcher);

// user가 존재하지 않아서 user.id에 접근할 때 error가 발생해 fetch가 실행되지 않습니다.
const { data } = useSWR(() => "/api/data?uid=" + user.id, fetcher);

key 값이 null 이거나 key 대신 함수를 사용할 경우 falsy한 값을 return 하면 fetch를 멈출 수 있습니다.

React Query

const { isIdle, data } = useQuery(["todos", userId], getTodosByUser, {
  // 쿼리는 userId 값이 존재할 때까지 실행되지 않습니다
  enabled: !!userId,
});
// isIdle 값은 enabled가 true가 될 때까지, fetch가 시작되기 전까지 true입니다.

사용자가 프로필 수정 기능을 통해 데이터를 수정해서, 프로필 정보를 refetch 하고 싶은 경우에는?

SWR

import { useSWRConfig } from "swr";

const Profile = () => {
  const { mutate } = useSWRConfig();
  const [profile, setProfile] = useState({ name: "jojiiiiyoung" });

  const handleEditProfile = () => {
    await updateProfile(profile);
    // unique key를 통해서 data가 invalid 상태임을 전달합니다.
    mutate(`/user/${userId}`);
  };
};

mutate 라는 함수를 통해 키에 해당하는 query를 refetch하도록 요청할 수 있다.

ReactQuery

import { useQueryClient } from "react-query";

const Profile = () => {
  const queryClient = useQueryClient();
  const [profile, setProfile] = useState({ name: "jojiiiiyoung" });

  const handleEditProfile = () => {
    await updateProfile(profile);
    // unique key를 통해서 data가 invalid 상태임을 전달합니다.
    // react query에서는 해당 데이터를 즉시 refetch 하게 됩니다.
    queryClient.invalidateQueries(`/user/${userId}`);
  };

invalidateQueries 함수를 통해 해당 key의 query가 invalid 하다고 알려주어, refetch하도록 한다.

사용자가 클라이언트에서 프로필을 수정하는 경우, 개발자는 이미 데이터가 어떻게 바뀌었는지 알 수 있는데요.refetch를 하지 않고 업데이트하고 싶다면?

SWR

const Profile = () => {
  const { mutate } = useSWRConfig();
  const [profile, setProfile] = useState({ name: "jojiiiiyoung" });

  const handleEditProfile = () => {
    await updateProfile(profile);
    // mutate 함수에 data 인자를 전달하면 refetch 없이 즉시 변경 가능합니다.
    mutate(`/user/${userId}`, profile, false);
  };
};

mutate함수에 키뿐 아니라, data를 전달하여 refetch없이 즉시 업데이트할 수 있다.

React Query

const Profile = () => {
  const queryClient = useQueryClient();
  const [profile, setProfile] = useState({ name: "jojiiiiyoung" });

  const handleEditProfile = () => {
    await updateProfile(profile);
    // setQueryData를 통해서 데이터를 직접 변경할 수 있습니다!
    queryClient.setQueryData(`/user/${userId}`, profile);
  };
};

setQueryData라는 함수를 통해 직접 업데이트를 할 수 있다.

참고자료를 보면서 이해하니, 쉽게 이해가 갔다.

728x90