라이프사이클(생애주기)는 리액트에서 중요한 개념 중 하나다. 리액트의 특장점이라고 할 수 있는 불변성과 관련된 개념이기 때문이다.
🔐 라이프사이클
부모 컴포넌트 A와 자식 컴포넌트 B가 있다. 컴포넌트 A는 state로 {name: "르탄이"}를 가지고 있고, 자식인 컴포넌트 B에게 name 값을 넘겨주었다. 컴포넌트 B는 받아온 name을 화면에 뿌려주고 있다. 컴포넌트 A의 state가 {name: "진도사우르스"}로 바뀌었을 때, 어떤 과정을 거쳐 바뀐 값을 화면에 보여주는지 라이프사이클을 그려보자.
1) 부모 컴포넌트 A의 constructor 메서드가 실행, "르탄이"라는 state를 가진 컴포넌트가 생성된다.
2) getDerivedStateProps가 실행되어서 A 컴포넌트가 가진 값(=르탄이)가 props에 들어간다.
3) A 컴포넌트의 render 메서드가 실행된다.
4) 자식 컴포넌트인 B의 constructor 메서드가 호출, A 컴포넌트로부터 받아온 props의 값(=르탄이)를 받아 자식 컴포넌트가 생성된다.
5) 자식 컴포넌트의 render 메서드가 실행되어 화면에 "르탄이"가 나타난다.
6) 자식 컴포넌트의 마운트가 완료되어 componentDidMount 메서드가 실행된다(첫 렌더링을 마친 후 실행되는 메서드).
7) 부모 컴포넌트의 componentDidMount가 실행된다. 컴포넌트가 DOM에 추가된 후 실행되는 것이다.
1) A 컴포넌트 에서 "르탄이"라는 state를 "진도 사우르스"로 변경, A 컴포넌트에서 업데이트가 발생한다.
2) shouldComponentUpdate 메서드가 실행되면서 리렌더링을 진행 여부를 결정한다. true나 false로 값이 반환되는데, A 컴포넌트의 스테이트가 변경되었기 때문에 true가 반환된다.
3) 바뀐 props(=진도사우르스)를 이용하여 A 컴포넌트가 리렌더링된다.
4) 마찬가지로 바뀐 props를 이어받아 B 컴포넌트가 리렌더링된다.
5) B 컴포넌트의 componenetDidUpdate 메서드가 실행된다. (componentDidMount는 최초 렌더 시 한 번만 실행)
6) A 컴포넌트의 componenetDidUpdate 메서드가 실행된다.
1) 컴포넌트가 DOM에서 제거될 때 ComponentWillUnmount가 실행된다.
❗ 여기서 잠깐! event listener는 등록되면 반드시 해제되어야 한다. 클래스형 컴포넌트에서는 컴포넌트가 화면에서 사라질 때(unmount 될 때) event listener를 해제한다. (componentWillUnmount에서요!) 그럼 라이프사이클 메소드를 사용할 수 없는 함수형 컴포넌트에서는 event listener를 해제할 때 어떻게 해야할까?
✏️ 클래스형 컴포넌트에서 componentDidMount와 componentDidUpdate의 역할을 함수형 컴포넌트에서는 useEffect 훅이 담당한다. 컴포넌트가 업데이트되거나 언마운트(제거)되기 전에 어떤 작업을 수행하고 싶다면, 즉 이벤트 리스너를 해제하려면 useEffect의 return 구문에서 removeEventListener를 통해 해제해주면 된다.
❗ 리액트에서 불변성이 왜 중요할까?
✏️ 웹 어플리케이션이 더욱 복잡해지고 동적이게 되면서 불변성은 프로그래밍에서 주목받게 된다. 변경 가능한 상태가 여러 곳에서 공유되면 여러 가지 문제가 발생하기 때문에 값이 변하지 않는 특성, 즉 불변성이 중요하다. 리액트에서 불변성을 지켜주는 이유는 리액트가 상태 업데이트를 하는 원리 때문이다. 리액트는 상태값을 업데이트 할 때 얕은 비교를 수행, 즉 객체의 속성 하나하나를 비교하는게 아니라 참조값만 비교하여 상태 변화를 감지한다. 즉 얕은 비교를 수행하는데, 얕은 비교는 계산 리소스를 줄여주기 때문에 리액트는 효율적으로 상태를 업데이트 할 수 있다. 업데이트 해야하는 DOM 요소를 찾아서 해당 부분만 업데이트하는 것이다. 리렌더링이 잦은 동적인 모던 웹에서 이는 빠른 퍼포먼스로 이어진다. 불변성을 지켜줌으로써 얻게 되는 또 다른 이점은 바로 사이드 이펙트를 방지하는 것이다. 즉 외부에 존재하는 원본 데이터를 직접 수정하지 않고, 원본 데이터의 복사본을 만들어서 값을 사용하기에 예상치 못한 오류를 사전에 방지할 수 있다.