useEffect
useEffect는 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정한다.
useEffect를 사이드이펙트를 다루는 훅이라고도 하는데,
사이드이펙트란 컴포넌트의 주요 목적인 화면에 렌더하는 것 이외의 효과를 말한다.
즉, ui를 생성하고 변경하는 것 이외에 애플리케이션에서 벌어지는 모든 변화를 사이드이펙트라고 할 수 있다.
예를 들면 http 요청을 보내거나, 타이머를 설정 및 관리하는 것 등이다.
다음과 같은 경우 useEffect가 유용하다.
1) 마운트/ 언마운트 시에 특정 함수를 실행하고 싶다면
2) 특정 값의 변화에 따라서 어떤 조작을 하고 싶다면
useEffect는 매개변수로 콜백 함수와 그 함수의 의존성을 담은 배열을 받는다.
의존성이란 무엇이 변했을 때 콜백 함수가 실행돼야 하는지 그 조건을 말한다.
이 의존성 배열에 뭘 넣느냐에 따라서 useEffect를 1의 용도로 사용할지, 2의 용도로 사용할지가 달라진다.
1) 의존성 배열을 빈 배열로 두게 되면 컴포넌트 함수가 처음 실행될 때만 콜백 함수를 실행한다.
이 경우 useEffect 내에서 함수를 리턴해 언마운트시에 클린업 함수가 실행되게 할 수 있다.
2) 특정 값의 변화에 따라서 조작을 하고 싶다면 의존성 배열에 그 값을 두면 된다.
state를 넣든 props를 넣든 간에 컴포넌트는 업데이트 되고, 그러면 useEffect도 다시 실행된다.
컴포넌트는 언제 업데이트되는가?
① props가 바뀔 때
② state가 바뀔 때
③ 부모 컴포넌트가 리렌더링될 때
클린업 함수
useEffect 내부에서 함수를 반환하면 그 함수는 클린업함수가 된다.
단, 클린업 함수는 컴포넌트 함수가 처음 실행될 때는 실행되지 않고 의존성이 변화됐을 때만 실행한다.
의존성 배열을 빈 배열로 둘 경우 컴포넌트가 언마운트되기 직전에만 클린업 함수가 실행된다.
이런 함수가 필요한 이유는 메모리 누수를 막기 위해서다.
useEffect의 효과가 거듭 쌓이기만 하고 치우지 않으면 메모리가 소모된다.
컴포넌트가 존재하는 동안 벌여 놨던 작업을 정리해 둬야 자원 낭비를 막을 수 있다.
useEffect 관찰하기
간단한 유효성 검사를 담은 로그인 폼에 콘솔 로그로 useEffect의 작동 과정을 찍어 보았다.
다음은 컴포넌트 코드의 일부이고, 컴포넌트가 렌더하기 직전에 'render'를 콘솔에 표시한다.
그리고 로그인 상태가 바뀔 때 useEffect를 실행하며 'useEffect'를 표시,
로그인에 성공해 화면이 바뀌면서 컴포넌트가 언마운트 될 때는 'cleanup'을 표시하게 해줬다.
useEffect(
function () {
console.log("useEffect");
return function () {
console.log("cleanup");
};
},
[isLoggedIn]
);
console.log("render");
return (
<React.Fragment>
<MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
<main>
{!isLoggedIn && <Login onLogin={loginHandler} />}
{isLoggedIn && <Home onLogout={logoutHandler} />}
</main>
</React.Fragment>
);
이렇게 해서 로그인을 진행하면 콘솔창에는 다음과 같이 찍히게 된다.
1. 첫 렌더링 시에 'render'가 표시
2. 첫 렌더링 직후 useEffect가 실행되면서 'useEffect' 표시
3. 로그인에 성공했을 때 isLoggedIn state가 업데이트되면서 'render' 표시
4. 그 직후 클린업 함수가 실행되고 'cleanup' 표시
5. 마지막으로 isLoggedIn state 변화로 인해 useEffect가 실행되며 'useEffect' 표시
이 순서대로 콘솔창에 표시되었다는 것을 알 수 있다.
setState 함수는 비동기로 작동한다
갑자기 setState 얘긴가 하면, setState가 비동기적으로 작동해서 발생하는 문제들을
useEffect를 사용해서 해결하는 방법이 많이 쓰이기 때문이다.
setState 함수는 비동기적으로 작동한다.
위의 로그인폼으로 돌아가면, 우리가 기대하는 것은 이메일이나 비밀번호를 입력할 때마다
입력된 내용이 state로 전달되고, 그 state를 바탕으로 유효성 검사를 하는 것이다.
그렇지만 실제로 돌아가는 방식을 보면, state가 입력된 내용을 즉각 반영하지 않는다는 걸 알 수 있다.
위 그림에서처럼, input에는 .com까지 입력이 완료되었으나
입력된 이메일 주소를 받는 state는 현재 .co까지만 반영되었다.
이처럼 setState가 비동기적으로 작동해 문제를 낳는 경우
setState 함수 내에서 이전 값을 받아서 함수 폼으로 작업을 처리하거나
useEffect의 의존성 배열에 해당 state를 넣어 문제를 해결할 수 있다.
(useEffect를 이런 용도로 사용하면 문제가 생길 수도 있다는 얘기도 있던데 이 부분을 더 알아보자!)
(내가 보려고 정리하는) 참고 자료
React — re-render vs re-evaluation issues with ease!!
https://rkraj604-hzb.medium.com/react-re-render-vs-re-evaluation-issue-with-ease-9eaf5ac99dba
A Complete Guide to useEffect
'React' 카테고리의 다른 글
[React] useReducer (2) | 2023.04.07 |
---|---|
[React] Context API (0) | 2023.04.06 |
[React] state, props (3) | 2023.03.26 |
[React] React Router 사용해 SPA 만들기 (0) | 2023.03.23 |
[React] 리액트의 원리와 특징 (0) | 2023.03.22 |