티스토리 뷰

Case 1 - dependency array 없이 data fetch

const [data, setData] = useState(); 
useEffect(async () => {
 const result = await something;
 setData(result.data);
})

문제점: 데이터를 불러온 후 setData를 하고 있기 때문에 리렌더링되고, 그러면 useEffect이 또 실행되므로 무한 루프가 발생한다.

Case2 - dependency array 있이 data fetch

const [data, setData] = useState(); 
useEffect(async () => {
 const result = await something;
 setData(result.data);
}, [])

개선된 점: dependency array를 빈 배열로 주었기 때문에 해당 컴포넌트가 마운트했을 때 한 번만 useEffect가 실행돼서 Case1처럼 무한 루프 문제가 없다.

문제점: react의 useEffect 함수는 clean up 함수를 리턴하거나 아무것도 리턴하지 말아야 한다. 그런데 위의 코드는 async 함수로 되어 있어서, 프로미스를 리턴하게 된다.

의아한 점은 return 키워드가 없는데도 프로미스가 리턴된다는 점이었는데, 확인해보니 그렇다. return 키워드가 없지만 암묵적으로 resolve value가 undefined인 프로미스가 리턴된다.

image

그래서 useEffect 룰에 위배되어 에러가 발생한다.

Case3 - 바로 async 함수를 넘기지 않고 따로 함수로 만든 뒤 data fetch

const [data, setData] = useState(); 
useEffect(() => {
  const fetchData = async () => {
    const result = await something;
    setData(result.data);
  }
  fetchData();
}, [])

이렇게 하면 아주 간단한 형태의 data fetch가 가능해진다.

Case4 - 바로 async 함수를 넘기지 않고 IIFE로 data fetch

const [data, setData] = useState(); 
useEffect(() => {
  ;(async () => {
    const result = await something;
    setData(result.data);
  })();
}, [])

함수를 따로 만들어서 호출하지 않고 IIFE로도 처리 가능하다.

Case5 - cleanup 함수를 추가

useEffect로 data fetch를 하고 나서 결과가 돌아오기 전에 컴포넌트가 언마운트되버리면, react는 언마운트한 컴포넌트에 setState를 하려고 시도한다. 이런 경우 메모리 릭이 일어날 수 있다는 에러가 발생하게 되므로, clean up 함수 추가가 필요하다.

const [data, setData] = useState(); 
useEffect(() => {
  const isCancelled = false;
  const fetchData = async () => {
    const result = await something;
    // cancel 됐으면 setData하지 않음
    if (isCancelled) {
      return
    }

    setData(result.data);
  }
  fetchData();

  return () => {
    isCancelled = true; 
  }
}, [])

clean up함수는 컴포넌트가 unmount되기 직전이나, useEffect가 다시 실행되기 직전에 실행된다. (useEffect cleanup function does not only run when our component wants to unmount, it also runs right before the execution of the next scheduled effect.)

그러므로 언마운트되기 전에 isCancelled는 true가 되므로 이후 데이터가 돌아와서 남은 코드를 실행할 때 setData에 가기 전에 return 되는 것이다.

Case6 - loading과 error 핸들링 추가

const [data, setData] = useState(); 
const [isLoading, setIsLoading] = useState(false); 
const [isError, setIsError] = useState(false); 

useEffect(() => {
  const fetchData = async () => {
    setIsLoading(true);

    try {
        const result = await something;
        setData(result.data);  
    } catch (error) {
      setIsError(true);
    }

    setIsLoading(false);
  }
  fetchData();
}, [])

이렇게 하면 로딩 상태와 에러 상태에 따른 렌더링 UI를 보여줄 수 있겠지만 위의 예제 코드는 보기 지저분하다.

이런 로딩/에러와 관련한 핸들링을 선언적으로 처리할 수 있도록 도와주는 것이 Suspense와 ErrorBoundary 인데 이는 다음 포스팅에서 다루도록 한다.

Ref

https://www.robinwieruch.de/react-hooks-fetch-data

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함