[React] Side Effect / useEffect / Clean up Effect

hongduhyeon·2022년 3월 21일
0
post-thumbnail
부러질지언정 휘어질 수 없다.

Side Effect 란?

이건 설명을 듣는 순간부터 헷갈렸다.
위에 말이 뭘 뜻하는가? 블로깅을 무조건 해야한다는 말이다.
마음이 시키는 블로깅

됐고, 본론으로 들어간다.

side effect함수가 실행되면서 함수 외부에 존재하는 값이나 상태를 변경시키는 등의 행위를 말한다. 이렇게만 말해서 알아듣는 사람은 코딩 천재가 아닐까 싶다.

물론 난 천재는 아닌듯하여 예제까지 같이 적을 예정,,,,

예를들어 함수에서 전역변수의 값을 변경하거나 혹은 함수 외부에 존재하는 버튼의 텍스트를 변경하거나, 파일을 쓰거나, 쿠키 저장, 네트워크를 통해 데이터를 송신하는 것 등이 있다.
좀 더 자세히 설명을 붙히자면 React 컴포넌트가 화면에 렌더링 된 이후에 비동기로 처리되어야 하는 부수적인 효과들을 side effect라고 칭한다. 대표적인 예시로 어떤 데이터를 가져오기 위해 외부 API를 호출할 때, 일단 화면에 렌더링 할 수 있는 것들은 먼저 렌더링하고 실제 데이터는 비동기로 가져오는 것이 권장된다. 요청 즉시 1차 렌더링을 함으로써 연동하는 API가 응답이 늦어지거나 응답이 없을 경우에도 영향을 최소화 시킬 수 있어서 사용자 경험 측면에서 유리하기 때문이다.

  • React에서 Side Effect 처리
function profile () {
	const message = `{name}님 환영합니다 !`; // 함수의 반환값을 생성한다.
    
  	// Bad
    document.title = `{name}의 개인정보`; // 함수 외부와 상호작용하는 Side Effec 코드
  	return <div>{message}</div>
}
  

위의 코드는 함수형 컴포넌트가 실행되고 결과를 생성하는 것과 무관한 document.title을 수정하고 있습니다. 이러한 코드는 작은 프로그램을 개발할 때는 문제가 없겠지만, 다양한 개발자들이 대규모 프로그램을 협업 개발할 때 실행상태를 예측하기 힘들게 한다고 한다.

만약 document.title이 지금과 같은 가벼운 상태가 아닌 꽤 무거운 작업을 수행하는 코드였다면 ? 컴포넌트가 렌더링 될 때마다 프로그램을 지연시키게 될 것이다.

하지만 여기서 react는 이러한 작업을 도와주는 역할을 하는 친구를 한명 친절히 데려와 줬다.
useEffect..!
바로 설명 들어간다.

useEffect 란 ?

방금 위에서 적은 Bad라는 주석이 있는 구문을 useEffect를 사용하면 좀 더 편리하게 side effect 작업을 진행할 수 있다. useEffect를 통해서 side effect 코드를 등록할 수 있고 !!!!

React가 알아서 적절한 시점에 side effect 작업을 수행해 줄 수 있다. 그리고 이러한 처리는 함수형 컴포넌트가 빠르게 렌더링 될 수 있게 도와주며, 프로그램을 복잡하게 만드는 side effect 영역을 함수와 분리할 수 있게 도와준다.

  • useEffect를 사용한 Side Effect 처리
function UserProfile({ name }) {
  const message = `${name}님 환영합니다!`;

  //Side-Effect 코드를 UseEffect로 분리
  useEffect(() => {
    document.title = `${name}의 개인정보`; 
  }, [name]);
  return <div>{message}</div>;
}

이와 같이 사용하게 되면 다른 개발자가 보더라도 컴포넌트에 side effect가 포함이 된다는 것을 알 수 있다.

관심사의 분리

effect는 내가 하고자하는 동작별로 분리되어 있는게 가장 좋다.
하나의 useEffect에 다 쓰면 유지보수 측면에서 본인의 눈을 질끈 감는 현상이 발생할 수도 있다.

ex) Data fetching의 경우
한 번에 useEffect(() => {} , [])안에 다 넣을 수 있지만 만약 프로필, 이미지, 댓글 등등 여러개의 fetch를 사용하면 나중에 어떤 것이 프로필이고 댓글인지 헷갈리게 된다. 그래서 여러개의 useEffect로 분리해야 하는 것이다.

Clean up Effect 란 ?

항상 그랬듯이 간단히 먼저 얘기해주자면 어... 음....
useEffect의 뒷처리를 담당해준다.

이게 무슨 말이냐면 useEffect 안에서 return 할 때 실행이 된다. 만약 컴포넌트가 마운트 될 때 addEventListener를 통해 이벤트를 추가하였다면 컴포넌트가 언마운트 될 때 이벤트를 삭제 해주어야 한다.
만일, 삭제해주지 않는다면 간단한 console.log를 찍어본다고 하더라도 100만명,500만명,1000만명의 사용자에게서 console.log가 나온다면 굉장히 무거워지고 자주 리렌더링 되며 현저히 속도가 내려가는걸 볼 수 있을 것이다.
메모리 누수

예를 들어 스크롤 이벤트를 가져오는 함수를 불러본다고 가정해보자.
이 스크롤 이벤트는 이 페이지를 벗어났을 때 이 이벤트 리스너를 더이상 필요로 하지 않는다. 그때 Clean up Effect를 사용하는 예제를 만들어보자

useEffect(() => {
  function handleScroll() {
    console.log(window.scrollY)
  }

  document.addEventListener("scroll", handleScroll)
  return () => {
    document.removeEventLisnter("scroll", handleScroll)
  }
}, [])

주의할 점은 단순히 컴포넌트가 생성되고, 사라지는 시점에만 clean up effect가 실행되는 건 아니라는 것이다. 다음 effect가 일어나기 전에, 꼭 이전 effect의 영향을 정리해줘야 한다.

profile
마음이 시키는 프론트엔드

0개의 댓글