useEffect
는 일반적으로 리액트에서 데이터 가져오기가 일어나는 곳이다.
데이터 가져오기는 비동기 함수를 사용하는 것을 의미하고 useEffect를 사용하는 것은 생각만큼 간단하지 않을 수 있다.
잘못된 방법
useEffect
에서 데이터 가져오기 수행하는 잘못된 방법 한가지:
...
// ❌ 이렇게 하지 마세요
useEffect(async () => {
const data = await fetchData();
}, [fetchData])
...
리턴하는 데이터가 소리를 지르는 코드가 될 것이다.
여기서 문제는 useEffect
의 첫번째 인수가 아무것도 반환하지 않거나(정의되지 않음) 함수를 반환하는 함수여야 하는데,
비동기 함수는 함수로 호출할 수 없는 Promise를 반환한다.useEffect
후크가 첫 번째 인수에 기대할 수 없다.
그렇다면 useEffect
내에서 비동기 코드를 어떻게 사용할까?
일반적으로 해결책은 useEffect 자체 내부에 데이터를 가져오는 것이다.:
...
useEffect(() => {
// 데이터 패치 함수 선언
const fetchData = async () => const data = await fetch('~');
// 함수 호출
fetchData()
// 에러 핸들링
.catch(console.error);
}, [])
...
주의할 점 -> 비동기 코드의 결과를 사용하려면 외부가 아니라 fetchData 함수 내부에서 사용해야 한다는 것.
이렇게 사용할 경우 아래와 같은 문제가 발생할 수 있는데, :
useEffect(() => {
const fetchData = async () => {
const data = await fetch('~');
const json = await data.json();
return json;
}
const result = fetchData()
.catch(console.error);
// 예상대로 동작하지 않음
setData(result);
}, [])
결과는 팬딩 된 Promise.
Promise {<pending>}
그렇다면 useEffect
내에서 비동기 코드의 결과를 어떻게 사용해야할까?
useEffect(() => {
const fetchData = async () => {
const data = await fetch('~');
const json = await response.json();
setData(json); // 여기!
}
fetchData()
.catch(console.error);;
}, [])
}, [])
useEffect 외부에서 함수를 추출해야하는 경우는 어떻게하지?
어떤 경우에는 useEffect 외부에서 데이터 가져오기 기능을 원한다.
이 경우 useCallback
으로 함수를 래핑하는데 종속성 배열에 주의해야한다.
useCallback
에 래핑되지 않은 경우 다시 렌더링할 때마다 업데이트되므로 재렌더링할 때마다 useEffect
가 트리거된다.
· · ·
// declare the async data fetching function
const fetchData = useCallback(async () => {
const data = await fetch('~');
setData(data);
}, [])
// useEffect는 fetchData를 적시에 호출하기 위해서 존재하게 된다.
useEffect(() => {
fetchData()
// make sure to catch any error
.catch(console.error);;
}, [fetchData])
· · ·
더 이상 setData
를 종속성 배열에 넣을 필요가 없게 됐다.
useEffect의 경우 콜백 실행을 의미.
useCallback의 경우 훅에서 반환되는 함수를 변경하는 것을 의미.
useEffect 내부에서 데이터 패치시 참고사항
호출이 매개변수에 의존한다고 가정해보자:
· · ·
useEffect(() => {
// declare the async data fetching function
const fetchData = async () => {
// get the data from the api
const data = await fetch(`https://yourapi.com?param=${param}`);
// convert the data to json
const json = await response.json();
// set state with the result
setData(json);
}
// call the function
fetchData()
// make sure to catch any error
.catch(console.error);;
}, [param])
· · ·
param
이 값을 변경하면 fetchData가 2번 호출된다.
이것이 빨리 발생하면 첫번째 호출이 두번째 호출 후에 리졸브될 수 있으므로 이전 값을 유지하게 된다.
그 문제를 해결하는 방법은 상태를 업데이트할지 여부를 제어하는 변수를 갖는 것이다.:
· · ·
useEffect(() => {
let isSubscribed = true;
// declare the async data fetching function
const fetchData = async () => {
// get the data from the api
const data = await fetch(`https://yourapi.com?param=${param}`);
// convert the data to json
const json = await response.json();
// 'isSubscribed'가 true일 때, 상태값을 업데이트함.
if (isSubscribed) {
setData(json);
}
}
// call the function
fetchData()
// make sure to catch any error
.catch(console.error);;
// isSubscribed 초기화
return () => isSubscribed = false;
}, [param])
· · ·
이것은 여러번 트리거 될 수 있는 useEffect에서 데이터를 가져올 때 사용할 수 있는 일반적인 패턴이다.
'coding > react' 카테고리의 다른 글
리코일, Atoms (0) | 2023.03.30 |
---|---|
버튼 애니메이션 1 with styled-component (0) | 2022.05.20 |
Next.js에서 백그라운드 이미지 적용해서 애니메이션 주기 (0) | 2021.11.17 |
zustand 사용하기 🚀 (0) | 2021.11.09 |
historyApiFallback의 역할 (0) | 2021.10.17 |
댓글