어떠한 문제를 맞닥뜨렸는가?
드림코딩의 유튜브 클론 코딩 프로젝트를 하면서, 제일 먼저 부딪혔던 에러 와 이에 대한 해결 방법에 대해서 이야기 해보려고 한다.
axios.get('data/list.json')
.then((Response)=>{
console.log(Response.data);
setVideoInfo(Response.data.items);
})
.catch((Error)=>{console.log(Error)});
다음과 같이, 코드를 작성하니, axios 가 무한대로 불러지면서, 노트북이 먹통이 되고, 아무런 작동이 되지 않고 꺼지게 되었다. 이는 드림코딩 강의에서도 중요한 게 강조하던 것이였다. 그러면서, 궁금한 게 있었다. 이러한 에러는 왜 뜨게 되는 것인가에 대한 궁금증이 커졌다. 그리고, 수업 때 분명히 배웠던 부분인 거 같은데 내가 놓쳤던 부분으로 생각하였다 . 내가 여태것 배운 것을 통한 생각으로는 React 에서 특정 component 를 re-render 할 일이 없는 경우라면, 저 부분이 다시 실행되지 않아야하는 것이라고 생각이 들었다. 이 부분에 대해서 정확히 파악해보기 위해, 강의 부분과 구글링과 공식문서를 통해 답을 찾아보고자 하였다.
해당 에러가 뜬 이유는 무엇일까 ?
해당 에러가 뜬 이유는 setVideoInfo(Response.data.items) ; 가 실행되면서, 해당 function 이 re-render가 되었기 때문이다. set 부분에 대해서 자세히 파악하고 있지 못했던 것 같다.
set functions, like setSomething(nextState)
The set function returned by useState lets you update the state to a different value and trigger a re-render.
출처: https://react.dev/reference/react/useState#setstate
위에서처럼 , React 의 공식문서에서도 set 함수는 state를 다른 값으로 업데이트 시키고 , re-render를 유발한 다고 말한다. 다시 말하자면 , axios 안에서 setVideoInfo() 가 re-render 를 시키면 , 다시 axios가 실행되고, 또 다시 setVideoInfo() 가 re-render 를 시키면 axios 가 실행되는 무한 루프가 발생했던 것이다.
useEffect 을 통한 해결 방법
공식문서에서는 " Fecthing data with Effects " 라고 해놓고 있고, 드림코딩 강의에서도, useEffect 을 통해서, 이를 해결했다. 그렇다면, useEffect 은 어떤 Hook 인 지 살펴보도록 하자.
useEffect is a React Hook that lets you synchronize a component with an external system.
useEffect ( setup , dependencies ? )
출처 : https://react.dev/reference/react/useEffect#fetching-data-with-effects
공식문서에서 useEffect Hook은 컴포넌트를 외부 시스템과 동기화시킬 수 있는 Hook 이라고 한다 .
" Fecthing data with Effects " 부분을 자세히 살펴보려고 한다.
공식문서에서 알려준 방식으로 위의 코드를 고치면 다음과 같이 된다.
useEffect(()=>{
let ignore = false ;
axios.get('data/list.json')
.then((Response)=>{
if ( !ignore ){
console.log(Response.data);
setVideoInfo(Response.data.items);
}
})
.catch((Error)=>{console.log(Error)});
return ()=>{
ignore = true ;
};
},[]);
이 경우에 조심해야할 것 이 있는데, 바로 useEffect 를 제대로 사용하지 않으면, " race conditions " 를 겪을 수도 있다는 것입니다. " race conditions" 가 무엇인지 위키백과를 통해 살펴보면, 둘 이상의 입력 또는 조작의 타이밍이나 순서 등이 결과값에 영향을 줄 수 있는 상태를 말합니다. 예를 통해 , 설명하자면, 특정 버튼을 클릭하면, axios 로 부터 특정 값 ( ' id ' ) 를 통해서 그에 따른 값을 가져온다고 합시다. 그리고, axios 로 부터 값을 가져오는데, 일부러 랜덤으로 시간이 1초에서 12초 정도 걸리도록 설정해 놓습니다. 이 경우에, 버튼을 여러번 클릭한다고 할 경우 , 우리는 어떤 값이 나올지 예측을 할 수 가 없습니다. 마지막에 눌렀던 작동으로 인해, 마지막 값이 나왔다고 확정지을 수 없습니다. 이러한 문제를 해결하기 위해, 이 경우에 , " Clean-up Function With Boolean Flag " 방법과 " Clean-up Function with AbortController " 방법과 async 와 await 을 통해서 해결할 수 있습니다. 이에 대한 것은 출처를 남겨 놓을테니 출처를 통해서 확인 해보시면 될 거 같습니다.
그렇다면, Fetching with useEffect 에는 단점이 없는가 ?
React 공식문서에서는 다음과 같이 말한다.
Writing fetch calls inside Effects is a
popular way to fetch data, especially in fully client-side apps.
This is, however, a very manual approach and it has significant downsides:
출처 : https://react.dev/reference/react/useEffect#fetching-data-with-effects
React 에서 Effect 를 통해 data 를 직접적으로 가져오는 것은 4가지 정도의 단점이 존재한다고 한다. 첫 번째, useEffect 는 서버에서 실행되지 않기 때문에, 다시 말해 , data 를 가져오려면 , 클라이언트 컴퓨터에서 모든 자바스크립트를 다운 받고, 앱을 Render 할 때에 data 를 불러올 필요가 있어지는데, 이러한 방식은 매우 비효율적이라고 한다. 두 번째, Effect 로 직접적으로 Fetching 하는 것은 " Network waterfalls " 가 발생하기 쉬워진다고 한다. 이는 부모 컴포넌트를 먼저 Render 하고, 그 다음에 자식 컴포넌트의 요소를 Render 하는 것이기에 , 병렬적으로 모든 DATA 를 가져오는 것보다 더 많은 시간이 걸리고 , 느리다는 것을 의미한다. 세번 째, 미리 로드하거나 데이터를 캐시하지 않습니다. 예를 들어, 컴포넌트가 마운트되고, 언마운트 되는 경우 , 그 때마다 데이터를 다시 불러와야합니다. 마지막으로, 일하는데 있어서, 편안하고, 효율적인 한경을 제공하는 데 어려움이 있습니다. 예컨대 , 레이스 조건과 같은 버그로 인해 어려움을 겪지 않는 방식으로 페치 콜을 작성할 때 관련된 상용 코드가 상당히 많습니다.
이러한 어려움들은 React Framework 또는 React Query 와 같은 라이프러리 등을 통해 해결 할 수 있다고 한다. 지금까지 useEffect 를 통한 data 를 fetch 하는 것에 대해서 이야기를 해봤다. 그리고, 이 부분을 공부하면서 useEffect hook 에 대해서 더 많은 것을 알게 된 거 같아서 좋았다. 앞으로도 내가 배운 것들에 대한 내용을 계속 이어나가보려고 한다.
참조사이트
https://react.dev/reference/react/useEffect#fetching-data-with-effects
https://maxrozen.com/race-conditions-fetching-data-react-with-useeffect
''취준' 시작' 카테고리의 다른 글
비동기 프로그래밍 (1) | 2023.08.23 |
---|---|
모던 자바스크립트 Deep Dive 1주차 회고록 (0) | 2023.07.30 |
React 에서 context 란 무엇인가 ? ( 리액트 비긴즈 02 ) (0) | 2023.07.23 |
국비학원이 끝나고 취준 시작 (0) | 2023.06.19 |