티스토리 뷰

Technology/React

Research for React-Query

캡틴테크 2022. 11. 16. 11:27

리액트로 사이드프로젝트를 진행하기위해 리서치를 해나가면서 프론트앤드가 서버랑 통신할때 사용하는 Axios 라이브러리 외에 효과적으로 통신한 데이터를 관리하는게 네트웍비용을 줄이는 중요한 요소이며, 서버의 데이터가 변경되었을때 바로바로 프론트에서 보여주는 동적인 기능들이 중요한데요. 오늘은 그런 요구사항들을 커버해줄 수 있는 리액트의 매커니즘인 React-Query에 대해서 살펴보고자 합니다.

Reference

리액트 쿼리를 도일을 위해 고민을 한 사람이 자세하게 내용 정리한 블로그

React-Query 도입을 위한 고민 (feat. Recoil) - 오픈소스컨설팅 테크블로그 - 강동희

 

React-Query 도입을 위한 고민 (feat. Recoil) - 오픈소스컨설팅 테크블로그 - 강동희

Web Frontend 개발을 할 때 React 를 사용하면서 마주하게 되는 여러 가지 문제점 중 하나는 state, 상태 관리에 관한 부분입니다. 프론트엔드 개발자라면 state 와 뗄 수 없는 인연을 맺고 있습니다.오늘

tech.osci.kr

리액트 쿼리 적용시 구조화한 내용을 잘 설명한 블로그

My구독의 React Query 전환기

 

My구독의 React Query 전환기

안녕하세요, 톡FE파트에서 My구독, 이모티콘 스토어를 개발하고 있는 Hugo입니다.My구독은 정기 결제를 통해 ‘이모티콘 플러스’, ‘톡서랍 플러스' 서비스를 이용할 수 있는 구독형 서비스입니

tech.kakao.com

React-Query의 주요장점

  • 서버 데이터 캐싱
  • 데이터 패칭 시 로딩, 에러 처리를 한 곳에서 처리 가능
  • Prefetching, Retry 등 다양한 옵션
  • 쉬운 상태관리

React-Query의 라이프 사이클

  • Fetching - 데이터 요청 상태
  • Fresh - 데이터가 프레쉬한 상태
    • 컴포넌트의 상태가 변경되더라도 데이터를 다시 요청하지 않습니다.
    • 새로고침 하면 다시 Fetching 합니다.
  • Stale - 데이터가 만료된 상태
    • 데이터가 만료되었다는 것은 서버에서 한번 프론트로 데이터를 주면 그 사이에 다른 유저가 데이터를 추가, 수정, 삭제 등을 할 수 있기 때문에 만료되었다고 합니다.(최신화가 필요한 데이터)
    • 컴포넌트가 마운트, 업데이트되면 데이터를 다시 요청
  • Inactive - 사용하지 않는 상태
    • 일정 시간이 지나면 가비지 콜렉터가 캐시에서 제거함
    • 기본값 5분
  • Delete - 가비지 콜렉터에 의해 캐시에서 제거된 상태
Feteching -> Fresh -> Stale -> Inactive -> Delete

데이터 패칭

기본적으로 axios를 이용해서 api를 호출하는 부를 만들고, 이를 Users에서 호출하여 Loading이 되었다면 성공할 경우 값이 들어오는 것을 볼 수 있습니다.

// API 호출
const getUserWithAxios = async () => {
  const { data } = await axios.get('http://localhost:8000/user');
  return data;
};
import {
  useQuery,
} from 'react-query';

const Users = () => {
	// 'users' 라는 queryKey값
	const query = useQuery('user', getUserWithAxios);
    // query 안에 data, isLoading, isSuccess, isError 등 다양한게 있다.
    console.log(query);
    
    return (
    	{
        !query.isLoading && (
          query.data.map((i: User) => (
            <li key={i.id}>{i.name}</li>
          ))
        )
      }
    );
}

데이터 업데이트

POST와 같이 데이터를 업데이트 하기 위해서 useMutation을 사용합니다.

const Users = () => {
  const [userId, setUserId] = useState<number>(5);
  // Query
  const { isLoading, data, isError } = useQuery('users', getUserWithAxios, {
    staleTime: 5000,
  });

  const mutation = useMutation((data) => axios.post('http://localhost:8000/user', data), {
    onSuccess: () => {
      setUserId(userId + 1);
    },
  });
  const handleSubmit = useCallback(
    (data) => {
      mutation.mutate(data);
    },
    [mutation],
  )
  if (isError) return <div>에러</div>;
  return (
    <ul>
      {
        !isLoading && (
          data.map((i: User) => (
            <li key={i.id}>{i.name}</li>
          ))
        )
      }
      <button onClick={() => handleSubmit({id: userId, name: `test${userId}`})}>유저 추가</button>
    </ul>
  );
};

다만 업데이트시 업데이트 사항만 보내기 때문에 프론트에서는 데이터가 Fresh 하지 않으므로 useState를 활용해서, setState를 해주는게 좋습니다.

const queryClient = useQueryClient();
  const [userId, setUserId] = useState<number>(5);
  // Query
  const { isLoading, data, isError } = useQuery('users', getUserWithAxios, {
    staleTime: 5000,
  });

 const mutation = useMutation((data: User) => axios.post('http://localhost:8000/user', data), {
    onMutate: (data: User) => {
      const previousValue = queryClient.getQueryData('users');
      console.log('previousValue', data);
      queryClient.setQueryData('users', (old: any) => {
        console.log('old', old);
        return [...old, data];
      });

      return previousValue;
    },
    onSuccess: (result, variables, context) => {
      console.log('성공 메시지:', result);
      console.log('변수', variables);
      console.log('onMutate에서 넘어온 값', context);
      setUserId(userId + 1);
    },
  });

실제 프로젝트에 사용하면서 느끼는 장단점들을 이후에 작성해보도록 하겠습니다.

댓글