기술/React

[React] 리액트 라이프 사이클 - useEffect

leedaramji 2024. 2. 22. 18:20

🌏 React Lifecycle 

 

Lifecycle이란 생애주기란 뜻이다. 생애주기란 일반적으로 시간에 흐름에 따라, 탄생부터 죽음에 이르는 순간에 따른 단계적인 과정이다. Lifecycle을 제어한다는 것에는 어떤 의미가 있을까? 컴포넌트가 탄생하고, 변화하고, 사라지고, 죽는 순간에 각각 어떤 작업을 수행시킬 수 있다는 것을 Lifecycle을 제어한다 또는 이용한다고 이야기할 수 있다.

 

이를 이용하면 컴포넌트가 처음 렌더링될 때 특정 동작을 하도록 만들거나, 업데이트할 때 적절할지 검사하거나, 페이지에서 사라질 때 메모리를 정리하는 등 여러 유용한 작업을 단계에 맞게 할 수 있다. 리액트 훅의 하나인 함수 useEffect를 이용하면 이 사이클을 쉽게 제어할 수 있다.

 

🌐 React 컴포넌트의 생애 주기 (생명 주기)

 

  • 탄생) Mount
    • 컴포넌트를 화면에 첫 렌더링
    • ex> 초기화 작업

 

  • 변화) Update
    • State나 Props의 값이 바뀌거나 부모 컴포넌트가 리렌더해 자신도 리렌더될 때
    • ex> 예외 처리 작업

 

  • 죽음) Unmount
    • 화면에서 사라질 때
    • ex> 메모리 정리 작업

 

📌 재렌더링? 


예를 들어 버튼을 클릭해서 State를 카운트업했을 때, 화면을 새로고침하지 않았는데도 수치가 바뀌고 화면 표시가 업데이트 된다. 이는 컴포넌트가 재렌더링되었기 때문이다.

가장 처음 화면을 표시할 때 렌더링이라고 한다. 그리고 'State가 변경될 때 함수 컴포넌트는 다시 처음부터 처리가 실행되고 State가 변경되면 다시 처음부터...'를 계속 반복하면서 차이가 있는 DOM을 감지하고 업데이트를 반영해서 화면을 표시한다. 이와 같이 '변경을 감지하고 컴포넌트를 다시 처리'하는 것을 재렌더링이라 부른다.

즉, 'State 업데이트 시 컴포넌트가 재렌더링되어 함수 컴포넌트가 다시 처음부터 실행된다'는 것이다.


⚠️ 참고로 매번 컴포넌트를 처음부터 실행한다 하더라도 맨 처음의 렌더링(컴포넌트의 마운트)과 재렌더링은 다르다. useState의 괄호로 설정한 초깃값은 마운트 시에만 적용되며 매번 초기화되지는 않는다.

 

🌐 React는 기본적으로 Lifecycle 마다 실행할 수 있는 메서드를 가진다.

 

  • Mount - ComponentDidMount
  • Update - ComponentDidUpdate
  • Unmount - ComponentWillUnmount

 

위의 메서드들은 Class형 컴포넌트에서만 사용 가능하기 때문에 함수형 컴포넌트에서는 사용할 수 없다. 이때 React Hooks를 사용하면 Class형 컴포넌트에서 사용 가능했던 기능을 함수형 컴포넌트에서도 사용 가능해진다. 함수형 컴포넌트에서 Class형 컴포넌트의 기능을 낚아채듯이 훔쳐와서 사용할 수 있도록 하는 것이다. 앞에 use 키워드를 붙여서 사용한다.

 

  • useState
  • useRef
  • useEffect

 

🌏 React Hooks란 무엇인가?

 

React Hooks는 2019년 6월 정식 출시된 기능이다. Class형 컴포넌트는 비교적으로 굉장히 많은 코드를 작성해야 하고, 복잡하며, 가장 치명적인 단점으로는 중복 코드를  굉장히 많이 써야 한다. 그래서 Class형 컴포넌트의 길어지는 코드 길이 문제와 중복 코드, 가독성 문제 등을 해결하기 위해 등장했다. 최신 리액트는 함수형 컴포넌트로 트렌디하게 모던하게 만들 수 있다.

 

🌏 useEffect

 

리액트에서 함수형 컴포넌트의 Lifecycle을 제어하기 위해서 useEffect라는 리액트 훅을 사용한다. 이는 어떤 값이 변경될 때마다 특정 코드를 실행하는 리액트 훅이다. 이를 "특정 값을 검사한다"라고 표현한다. 특정 작업을 처리할 코드를 실행시켜 주고 싶다면 useEffect를 사용하면 된다.

이런 기능이 존재하는 이유는 컴포넌트가 재렌더링을 몇 번이고 반복하기 때문이다. State 수가 많아지면 재렌더링 횟수도 늘어난다. 따라서 재렌더링할 때마다 처리를 실행하는 것은 비용(시간)을 낭비하게 되므로 값이 변했을 때만 실행하고 싶은 경우가 생긴다. 이런 부작용을 제어하고자 할 때 useEffect를 사용한다.

기본적으로 useEffect 훅은 인자로 콜백을 받는다. 콜백 함수란 다른 함수에 인자로 전달된 함수를 의미한다. 콜백 함수 내부에 원하는 작업을 처리해 줄 코드를 작성하면 된다.

 

[사용 방법]

 

📌 useEffect(callback, [의존성 배열 deps])

 

  • useEffect( () => { //Todo... }, [ ] );
    • 첫 번째 인자로 콜백함수를 전달
    • 두 번째 인자로 배열을 전달 / (Dependency Array (의존성 배열)
    • value가 있는 배열  
      • 화면에 첫 렌더링 될 때 실행
      • 배열 내에 들어있는 값이 변화하면 콜백 함수 실행
      • 의존성 배열 요소가 여러 개 있을 때 배열 요소 중 하나가 변경되어도 useEffect는 콜백 함수를 실행한다.
    • 빈 배열을 전달
      • 화면에 첫 렌더링 될 때만 실행
      • Mount 시점에 뭔가를 하고 싶으면 빈배열을 전달해주고, 콜백함수에 하고 싶은 일을 넣는다.

 

  • useEffect( () => { //Todo... } );
    • 두 번째 요소인 의존성 배열에 아무것도 전달하지 않는 경우
    • 컴포넌트가 Update(렌더링) 될 때마다 콜백 함수 실행
      1. 마운트, 업데이트 시점 모두 콜백 함수를 호출
      2. Ref 객체와 조건문으로 특정 시점에만 코드를 실행하게 만들 수도 있다.
    • 3번 출력하면
      • 1번은 처음 페이지에 렌더링하는 마운트 시점 한 번 출력
      • 컴포넌트를 리렌더하는 업데이트 시점 두 번의 결과 출력

 


 

1. 렌더링될 때마다 매번 실행 - 렌더링 이후

useEffect(() => {
	console.log('렌더링🙂');
});

 

=> 무거운 작업시 비효율적

 

2. 마운팅 + count가 변화될 때 마다 실행

useEffect(() => {
	console.log('count 변화 📒');
}, [count]);

 

3. 마운팅 + name이 변화될 때 마다 실행

useEffect(() => {
	console.log('name 변화 📒');
}, [name]);

 

4. 컴포넌트의 마운트 제어하기 - Mount 시점에만 콜백 함수 실행

useEffect(() => {
	console.log('마운팅😄');
}, []);

 

    => 컴포넌트의 마운트를 제어한다.
    => 가장 처음 컴포넌트를 표시할 때만 실행되는 처리를 의미한다.
    => 화면을 표시하고 초기 데이터를 얻을 때 등에 자주 사용된다.

 


 

📒 라이프 사이클 제어하기 - 마운트 시점 제외하고 업데이트 시점에만 콜백 함수 실행

const didMountRef = useRef(false);

useEffect(() => {
	if (!didMountRef.current) {
    	didMountRef.curren = true;
     	return;
   	} else {
   	 console.log("컴포넌트 업데이트!");
	}
});

 

의존성 배열을 전달하지 않을 경우 컴포넌트가 렌더링될 때마다 콜백 함수가 실행된다. Ref 객체와 조건문으로 특정 시점에만 코드를 실행하게 만들 수도 있다.

현재 App 컴포넌트를 페이지에 마운트했는지 판단하는 변수 didMountRef를 Ref 객체로 생성한다. 초깃값으로 false를 설정한다 (*Ref 객체는 돔 요소를 참조하는 것뿐만이 아니라 컴포넌트의 변수로도 자주 활용된다.)

내부의 조건문으로 마운트 시점(didMountRef=false)에 호출하면 아무것도 출력하지 않고 함수를 종료하고, 업데이트 시점(didMountRef=true)에 호출하면 문자열을 콘솔에 출력한다.

 

 

📒 컴포넌트 언마운트 제어하기 - Clean Up

 

useEffect(() => {
	const intervalID = setInterval(() => {
    	console.log("깜빡");
    }, 1000);
    
    return () => {
    	console.log("클린업");
        clearInterval(intervalID);
    };
});

 

리액트 컴포넌트의 언마운트 시점을 제어하기 위해서는 먼저 클린업 기능을 이해해야 한다. 클린업이란 원래 '청소'라는 뜻이다. 프로그래밍에서 이 개념은 특정 함수가 실행되고 종료된 후에, 미처 정리하지 못한 사항을 처리하는 일이다. 

useEffect의 콜백 함수가 반환하는 함수를 클린업 함수라고 한다. 이 함수는 콜백 함수를 다시 호출하기 전에 실행된다. 따라서 컴포넌트를 렌더링할 때마다 새 인터벌을 생성하고 기존 인터벌은 삭제한다.

useEffect의 콜백 함수가 또 다른 함수를 반환하는 클린업 기능을 이용하면 인터벌같이 종료 이후에도 남아 있는 작업을 청소할 수 있다.

 

 

 

 

 

📕참고: 한 입으로 잘라먹는 리액트 _ 이정환/ 인프런 강의

'기술 > React' 카테고리의 다른 글

[React] 조건부 렌더링  (0) 2024.02.26
[React] React developer tools  (0) 2024.02.22
[React] List와 key의 중요성  (0) 2024.02.20
[React] 가상 돔 (Virtual DOM)이란 무엇일까?  (0) 2024.02.20
[리액트] create-react-app  (0) 2024.02.05