본문 바로가기
Library | Framework/React

[React] 함수형 컴포넌트로 라이프 사이클 구현하기 - useEffect hook

by 나는김혜린 2022. 1. 15.

서론

이번 글의 내용은 나도 이해를 잘 못한 부분이라 설명이 난해할 수 있다.

라이프사이클이란 생명주기를 뜻하는데, 쉽게 말하면 컴포넌트가 렌더링되고 삭제되는 과정을 뜻한다.

참고로 이때까지 만든 컴포넌트들은 라이프사이클이 없는 컴포넌트들이었다...

무튼 만들어보자!

 

클래스형으론 어떻게 만들까?

클래스형으로 만들 때에는 componentWillMount -> render -> componentDidMount - > componentWillUnmount 메서드들이 이러한 순서를 가진다.

 

* mount : 어떤 컴포넌트가 생성된다. = 화면에 그려지다.

 

componentWillMount라는 메서드를 구현해서 그 안에 필요한 코드를 가져다 놓는 식으로 마운트되기 직전에,

즉 render 메서드가 호출되기 전에 해야 할 일을 수행할 수 있다.

 

var classStyle = 'color:red'; // class 바깥에

UNSAFE_componentWillMount() {
    console.log('%cclass => componentWillMount', classStyle);
  }

  componentDidMount() {
    console.log('%cclass => componentDidMount', classStyle);
  }

  shouldComponentUpdate(nevtProps, nextState) {
    console.log('%cclass => shouldComponentUpdate', classStyle);
    return true;
  }
  
  UNSAFE_componentWillUpdate(nevtProps, nextState) {
    console.log('%cclass => componentDidUpdate', classStyle);
  }

  componentDidUpdate(nevtProps, nextState) {
    console.log('%cclass => componentDidUpdate', classStyle);
  }

저번 글에서 만들었던 ClassComp 컴포넌트 render 함수 바깥에 이 코드를 적어보자.

componentWillMount, componentWillUpdate는 리액트 17 버전 이상부터는 사용할 수 없어 앞에 UNSAFE_를 붙여줘야한다.

이대로 실행해보면 콘솔창에 componentWillMount -> render -> componentDidMount 이 순으로 출력되는 걸 볼 수 있다.

정리해보면, componentWillMount는 render함수가 실행되기 전에 해야 할 일을 구현하고,

componentDidMount는 render함수가 실행되고 나서 처리해야할 일이나 네트워크로 처리해야하는 코드들을 구현한다.

그리고 render함수가 실행되고 state나 props가 바뀌면 다시 render 함수가 실행되는 걸 볼 수 있다.

이때 shouldComponentUpdate에서 render 함수를 다시 호출할 필요가 있는지 없는 결정해

true를 반환하면 render를 호출하고, false를 반환하면 render를 호출하지 않는다.

-> 버튼을 클릭해보면 shouldComponentUpdate가 실행되는 걸 확인할 수 있음.

 

componentWillUnmount는 컴포넌트가 소멸될 때 호출되는데, 우리 코드에는 컴포넌트가 소멸되지 않아 호출되지 않았다.

 

함수에서 라이프사이클 구현하기 - 준비

함수형으론 라이프사이클을 어떻게 만들까?

일단 쉽게 알아보기 위해서 변수를 만들어보자.

var funcStyle = 'color:blue';
var funcId = 0;
function FuncComp(props) {
  생략
  console.log('%cfunc => render ' + (++funcId), funcStyle);

funcStyle은 알아보기 위한 CSS 속성값이고 funcId는 호출할 때마다 1씩 증가하는 변수이다.

 

함수에서 라이프사이클 구현하기 - useEffect

리액트 함수형 컴포넌트에선 훅을 사용한다. 라이프사이클을 구현하기 위해선 useEffect라는 훅을 사용하는데,

이 useEffect는 함수 컴포넌트(FuncComp)를 반환하기 전에 호출하면 된다.

 

useEffect는 첫 번째 인자와, 반환값은 무조건 함수여야 한다.

또한, 클래스형 컴포넌트의 componentWillMount나 componentDidUpdate와 비슷하다고 볼 수 있다.

그리고 여러 개의 useEffect를 사용할 수도 있다.

 

  useEffect(function() {
    console.log('%cfunc => useEffect number (componentDidMount & componentDidUpdate) ' + (++funcId), funcStyle);
    document.title = number;

    return function() {
      console.log('%cfunc => useEffect number return (componentDidMount & componentDidUpdate) ' + (++funcId), funcStyle);
    }
  }, [number]);

  useEffect(function() {
    console.log('%cfunc => useEffect date (componentDidMount & componentDidUpdate) ' + (++funcId), funcStyle);
    document.title = _date;

    return function() {
      console.log('%cfunc => useEffect date return (componentDidMount & componentDidUpdate) ' + (++funcId), funcStyle);
    }
  }, [_date]);

이런 식으로 구현해볼 수 있는데, 여기서 useEffect의 장점이 들어있다.

number이 바꼈을 때는 number의 useEffect만 호출되고, date가 바꼈을 때는 date의 useEffect만 호출된다.

즉, 바뀐 값에 대한 처리만 함으로써 성능을 굉장히 손쉽게 향상시킬 수 있다.

 

함수형 컴포넌트와 클래스형 컴포넌트가 사라지게!

function App() {
  var [funcShow, setFuncShow] = useState(true);
  var [classShow, setClassShow] = useState(true);

  return (
    <div className='App'>
      <h1>Hello World</h1>
      <input type="button" value="remove func" onClick={
        function() {
          setFuncShow(false);
        }
      } ></input>

      <input type="button" value="remove class" onClick={
        function(){
          setClassShow(false);
        }
      }></input>
      {funcShow ? <FuncComp initNumber={2}></FuncComp> : null }
      {classShow ? <ClassComp initNumber={2}></ClassComp> : null}
    </div>
  );
}

이 코드를 작성하고 구현해보자.

remove 버튼을 눌렀을 때 componentWillUnmount가 호출되는 것을 볼 수 있다.

 

담소

처음엔 뭔 내용인지도 모르겠고 어려웠는데, 티스토리 쓰면서 정리가 된 듯!!

다음 목차는 React 라우터에 관한 내용인 것 같은데 벌써 기대가 된당 ㅎㅎ

댓글