어쩌다 보니 리액트 쿼리에 대해서 계속 포스팅을 하고 있다.
오늘 알아볼 내용은 React Query를 사용해서 데이터를 패칭하는 방법에 대해 알아보고자 한다.
기존에 나는 데이터를 패칭할 때 useEffect
훅을 사용해서 의존성 배열에 빈 배열 ([]
)을 줌으로 써 처음 렌더링되는 상황에 데이터를 패칭할 수 있도록 구현해왔다.
하지만 리액트 스터디를 하며 공부해 본 내용을 토대로 봤을 때 이는 권장되지 않는 방법이다.
왜 권장되지 않는가에 대해서 알아보기 전에 useEffect에 대해서 정말 간단하게 짚고 넘어가보자.
📌 useEffect
- useEffect는 의존성 배열의 값을 살피며 state나 props의 변화에 따라 일어나는 렌더링 과정 속에서 콜백을 실행해 부수 효과를 일으키는 함수라고 볼 수 있다.
- 의존성 배열로 아무것도 넣지 않는다면 비교할 요소가 없다고 생각해 렌더링 때마다 실행이 필요하다고 여기고 무한 실행에 빠질 수 있다.
- 빈 배열(
[]
)이 들어갈 경우 처음 렌더링 될 때만 콜백이 호출된다. 이는 클래스 컴포넌트의componentDidMount
와 비슷한 기능을 한다.
여기까지는 우리가 흔히 알고 있는 내용이다.
이러한 useEffect
를 사용할 때 주의할 점이 몇 가지 있는데 의존성 배열에 빈 배열을 사용하는 것을 가급적이면 자제하라는 것이다.
위에서 보면 알 수 있듯이 useEffect
는 의존성 배열로 전달한 값의 변경에 의해 실행되야 하는 훅이다.
그러나 의존성 배열에 값을 전달하지 않고 단순히 최초 렌더링 때 한 번 실행하도록 한다면 이 콜백 함수로 인해 발생하는 부수 효과가 실제로 관찰해서 실행돼야 하는 값과는 별개로 작동한다는 것을 의미한다.
즉, 컴포넌트의 state, props와 같은 어떤 값의 변경과
useEffect
의 부수 효과가 따로 별개로 작동하게 된다.
react query로 넘어가기 전에 한 가지 더 짚고 넘어갈 내용은 useEffect
첫 번째 인수인 콜백 함수로 비동기 함수를 넣는 것에 대해 알고 넘어가자.
나는 개발을 하며 데이터 패칭을 할 때 useEffect를 활용해 의존성 배열을 빈 배열로 둠으로써 최초 렌더링 시 비동기 함수를 사용해서 데이터 패칭을 진행했다.
하지만 비동기 함수를 useEffect
내에 넣게 되면 비동기 함수의 응답 속도에 따라서 결과가 이상하게 나타날 수 있다.
이러한 경우를 경쟁 상태라고 한다.
💡 경쟁 상태
경쟁 상태(race condition)은 일반적으로 여러 프로세스나 스레드에서 공유된 자원에 동시에 접근하거나 수정하려고 할 때 발생하는 상태를 나타낸다. 이는 예상치 못한 결과를 가져올 수 있다.
비동기적으로 작업이 처리되면서 응답 속도에 따라서 결과가 이상하게 나타난다는 것이다.
만약 useEffect 내에서 비동기 함수를 사용하게 되면 이 내부에서 비동기 함수가 생성되고 실행되는 것을 반복하기 때문에 클린업 함수에서 비동기 함수에 대한 처리를 해주는 것이 좋다.
예를 들어 fetch를 사용해 요청을 한다면 abortController를 사용해 이전에 보낸 요청을 취소해 주는 것이다.
위의 내용들을 종합해봤을 때 useEffect
를 사용해서 데이터 패칭 등의 비동기 작업을 하는 것은 이후 처리가 필요할 뿐더러 의존성으로 빈 배열을 사용하는 것은 useEffect
의 취지에도 어긋난다.
이를 해결하기 위해 React-Query
를 활용하면 라이브러리에서 제공해주는 다양한 기능을 사용할 수 있을 뿐더러 코드가 줄어들어 직관적이게 변경이 가능하다!
(설치 과정 및 index.js에 설정하는 과정은 생략하겠습니당)
import axios from 'axios';
export async function fetchData(){
return await axios.get('url').then((res) => res.json);
}
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 데이터 패치 구현 방법 참고