[React Query] 데이터 패치해보기 (feat. useEffect 를 권장하지 않는 이유)

SSO·2024년 5월 17일
0

Web-Develop-Study

목록 보기
16/18

어쩌다 보니 리액트 쿼리에 대해서 계속 포스팅을 하고 있다.
오늘 알아볼 내용은 React Query를 사용해서 데이터를 패칭하는 방법에 대해 알아보고자 한다.

📄 기존 방식

기존에 나는 데이터를 패칭할 때 useEffect훅을 사용해서 의존성 배열에 빈 배열 ([])을 줌으로 써 처음 렌더링되는 상황에 데이터를 패칭할 수 있도록 구현해왔다.

하지만 리액트 스터디를 하며 공부해 본 내용을 토대로 봤을 때 이는 권장되지 않는 방법이다.

왜 권장되지 않는가에 대해서 알아보기 전에 useEffect에 대해서 정말 간단하게 짚고 넘어가보자.

📌 useEffect

  • useEffect는 의존성 배열의 값을 살피며 state나 props의 변화에 따라 일어나는 렌더링 과정 속에서 콜백을 실행해 부수 효과를 일으키는 함수라고 볼 수 있다.
  • 의존성 배열로 아무것도 넣지 않는다면 비교할 요소가 없다고 생각해 렌더링 때마다 실행이 필요하다고 여기고 무한 실행에 빠질 수 있다.
  • 빈 배열([])이 들어갈 경우 처음 렌더링 될 때만 콜백이 호출된다. 이는 클래스 컴포넌트의 componentDidMount와 비슷한 기능을 한다.

여기까지는 우리가 흔히 알고 있는 내용이다.

이러한 useEffect를 사용할 때 주의할 점이 몇 가지 있는데 의존성 배열에 빈 배열을 사용하는 것을 가급적이면 자제하라는 것이다.


❗️왜 그럴까

위에서 보면 알 수 있듯이 useEffect의존성 배열로 전달한 값의 변경에 의해 실행되야 하는 훅이다.

그러나 의존성 배열에 값을 전달하지 않고 단순히 최초 렌더링 때 한 번 실행하도록 한다면 이 콜백 함수로 인해 발생하는 부수 효과가 실제로 관찰해서 실행돼야 하는 값과는 별개로 작동한다는 것을 의미한다.

즉, 컴포넌트의 state, props와 같은 어떤 값의 변경과 useEffect의 부수 효과가 따로 별개로 작동하게 된다.


📌 useEffect 콜백 인수로 비동기 함수를 넣는 것에 대해

react query로 넘어가기 전에 한 가지 더 짚고 넘어갈 내용은 useEffect 첫 번째 인수인 콜백 함수로 비동기 함수를 넣는 것에 대해 알고 넘어가자.

나는 개발을 하며 데이터 패칭을 할 때 useEffect를 활용해 의존성 배열을 빈 배열로 둠으로써 최초 렌더링 시 비동기 함수를 사용해서 데이터 패칭을 진행했다.

하지만 비동기 함수를 useEffect 내에 넣게 되면 비동기 함수의 응답 속도에 따라서 결과가 이상하게 나타날 수 있다.
이러한 경우를 경쟁 상태라고 한다.

💡 경쟁 상태
경쟁 상태(race condition)은 일반적으로 여러 프로세스나 스레드에서 공유된 자원에 동시에 접근하거나 수정하려고 할 때 발생하는 상태를 나타낸다. 이는 예상치 못한 결과를 가져올 수 있다.
비동기적으로 작업이 처리되면서 응답 속도에 따라서 결과가 이상하게 나타난다는 것이다.


만약 useEffect 내에서 비동기 함수를 사용하게 되면 이 내부에서 비동기 함수가 생성되고 실행되는 것을 반복하기 때문에 클린업 함수에서 비동기 함수에 대한 처리를 해주는 것이 좋다.


예를 들어 fetch를 사용해 요청을 한다면 abortController를 사용해 이전에 보낸 요청을 취소해 주는 것이다.


위의 내용들을 종합해봤을 때 useEffect를 사용해서 데이터 패칭 등의 비동기 작업을 하는 것은 이후 처리가 필요할 뿐더러 의존성으로 빈 배열을 사용하는 것은 useEffect의 취지에도 어긋난다.

이를 해결하기 위해 React-Query를 활용하면 라이브러리에서 제공해주는 다양한 기능을 사용할 수 있을 뿐더러 코드가 줄어들어 직관적이게 변경이 가능하다!

💻 React Query를 사용해 데이터 패칭을 해보자

(설치 과정 및 index.js에 설정하는 과정은 생략하겠습니당)

  1. fetch 함수 생성
  • api를 별도 파일로 따로 분리해서 사용했다.
  • 그 외의 방법으로는 사용할 컴포넌트 내에서 함수를 생성해서 사용해도 가능하다.
  • useQuery 내에서 두 번째 인수 자리에 바로 함수를 넣어도 된다.
import axios from 'axios';

export async function fetchData(){
	return await axios.get('url').then((res) => res.json);
}

  1. useQuery
import { useQuery } from "@tanstack/react-query';
import { fetchData } from '파일 경로';

interface DataProps {
	id: string;
  	name: string;
    num: number;
}

const App = () => {
	// 쿼리키, 호출할 함수 순서
	const {isPending, error, data} = useQuery<dataProps[]>('fetch', fetchData)
    
    if(isLoading){
    	return <div>Pending..</div>;
    }
  
  	if(isError){
    	return <div>Error</div>;
    }
}

코드를 작성하는 방법은 여러가지 있으니 다양한 방법으로 연습해보면 좋을 것 같다~!


⚙️ 참고 자료

🔗 [모던 리액트 Deep Dive] useEffect 부분 참고
🔗 useEffect 및 react-query 적용 방법 참고
🔗 react-query 데이터 패치 구현 방법 참고

profile
👩🏻‍💻👊🏻⭐️

0개의 댓글