
이미지 출처
공식문서
React의 class형 컴포넌트는 위 이미지와 같은 생명주기를 가집니다.
Mounting, Updating, UnMounting의 3가지 상황이 있고,
각 상황에 맞는 라이프 사이클 메서드를 거치면서 컴포넌트가 DOM에 올라가게 됩니다.
라이프 사이클과 비동기에 대해 이해하면 리엑트에서 본인이 원하는대로 동작하는지 아닌지 판단하기 쉬워집니다.
생명주기 메서드는 3가지 단계를 가지고 있습니다.
각 단계에 맞게 코드를 짜야 컴포넌트가 의도한대로 동작합니다.
Render 단계
이 단계에서는 사이드 이펙트 없이 순수하게 지닌 값을 통해 렌더링 됩니다.
사이드 이펙트란 state를 업데이트 하는 행위 등을 말하며, 이 시점에서는 컴포넌트를 일시정지, 중단, 렌더, 재시작 등이 가능합니다.
Pre-commit 단계
업데이트에서의 getSnapshotBeforeUpdate만 이 단계에 해당하는데, 렌더를 마치고 DOM에 반영되기 직전에 일어납니다.
이 상황에서도 DOM을 읽을 수 있습니다.
Commit 단계
변경사항들을 DOM에 적용시킵니다.
적용 이후에 componentDidMount, ComponentDidUpdate 메서드를 호출하여 사이드 이펙트를 발생시킬 수 있습니다.
컴포넌트가 처음으로 불려져 생성될 때 입니다.
Re-Render 시에는 불리지 않고 오직 한번만 불려지게 됩니다.
constructor
컴포넌트의 생성자 입니다.
컴포넌트가 생성되면서 가장 먼저 실행 됩니다.
state나 변수, 그리고 클래스를 이곳에서 초기화 해줍니다.
tsx
1 constructor(props: OwnProps) { 2 super(props); 3 4 this.state = { 5 example : 'exp', 6 } 7 }
super()는 빈 객체를 만들고 this에 이 객체를 할당하는 일을 부모 클래스에게 기대합니다.
자식 클래스의 인스턴스에는 고유 멤버와 부모 클래스의 모든 멤버도 포함 되었기 때문에 반드시 호출해야 합니다.
super(props)의 props는 넣어주지 않더라도 클래스에서 인식은 할 수 있습니다.
하지만 constructor 단계에서는 props가 undefined 상태가 되는데 constructor에서 props를 사용하기 위해선 반드시 넣어줘야 합니다.
❗constructor에서 state에 props를 넣을 때
외부의 props가 변경되어도 constructor에서 초기화를 해주게 된다면 state는 변하지 않습니다.
외부 props에 따라 동작하게 하려면 update시에도 불려지는 getDerivedStateFromProps에서 넣어주거나, 혹은 props그 자체로 이용해야 합니다.
getDerivedStateFromProps
이 메서드는 props로 받아온 데이터를 state에 넣어줄 때 사용하는 메서드입니다.
일반적으로 사용되는 함수는 아니며, state가 props에 의존해야 하는 경우에만 사용합니다.
tsx
1 getDerivedStateFromProps() { 2 if(props.firstName + props.lastName !== state.name) { 3 return { 4 name : props.firstName + props.lastName, 5 } 6 } 7 return null; 8 }
render
컴포넌트를 렌더링 해주는 메서드입니다.
클래스 컴포넌트에서 반드시 필요로 하는 메서드이고, 실제 DOM에 올라가게 될 태그들 입니다.
tsx
1 render() { 2 return ( 3 <div> 4 <input type='text' value={this.state.text}> 5 </div> 6 ) 7 }
componentDidMount
컴포넌트가 마운트된 직후 실행됩니다.
네트워크 요청을 통한 초기화 작업을 할 때 자주 사용됩니다.
tsx
1 componentDidMount() { 2 ajax.get("/example").then(......); 3 }
state가 변화하거나 props가 변화하거나 혹은 forceUpdate() 메서드를 사용할 때 발생합니다.
getDerivedStateFromProps
생성시와 마찬가지입니다. props에 대해 tate가 갱신됩니다.
shouldComponentUpdate
성능 최적화 메서드입니다.
이 메서드는 컴포넌트가 리렌더링을 할지 말지 결정해줍니다.
true값을 반환하면 리렌더링을 진행하고, false값을 반환하면 리렌더링이 일어나지 않습니다.
리엑트는 부모 컴포넌트가 리렌더링 되면 자식 컴포넌트도 전부 리렌더링이 일어납니다.
이 메서드를 활용하면 부모 컴포넌트의 리렌더링에 자식 컴포넌트가 자유로워집니다.
기본타입(string, number 등..)은 그냥 비교해도 상관없으나, 참조타입(object, array)등은 ❗얕은 비교를 해야만 값 비교가 가능합니다.
tsx
1 shouldComponentUpdate(nextProps, nextState) { 2 return this.props.data !== nextProps.data; 3 }
render
생성시와 마찬가지로 새로운 결과값이 반영된 컴포넌트를 렌더해줍니다.
getSnapshotBeforeUpdate
이 메서드는 컴포넌트의 변화를 DOM에 반영하기 직전에 호출되는 메서드입니다.
스크롤바 위치처럼 업데이트 직전의 값을 참고할 때 쓰이며,
이 메서드에서 componentDidUpdate메서드로 새로운 값을 넘겨줄 수 있습니다.
일반적인 상황에선 쓰이지 않으나 스크롤 이벤트 같은 경우에 필요합니다.
componentDidUpdate
컴포넌트가 업데이트 된 후에 불려집니다.
state나 props의 변화에 따른 로직을 수행할 때 사용하기 적절합니다.
tsx
1 // getSnapshotBeforeUpdate 미사용 2 componentDidUpdate(prevProps, prevState) { 3 if (this.props.data !== prevProps.data) { 4 this.flag = true; 5 } 6 } 7 8 // getSnapshotBeforeUpdate 사용 9 getSnapshotBeforeUpdate(prevProps, prevState) { 10 if (prevProps.list.length < this.props.list.length) { 11 const list = this.listRef.current; 12 return list.scrollHeight - list.scrollTop 13 } 14 return null; 15 } 16 17 componentDidUpdate(prevProps, prevState, snapshot) { 18 if (snapshot !== null) { 19 const list = this. listRef.current; 20 list.scrollTop = list.scrollHeight - snapshot; 21 } 22 }
컴포넌트가 제거될 때 일어납니다.
componentWillUnmount
컴포넌트가 DOM에서 사라지기 직전에 호출됩니다.
타이머 제거, 네트워크 요청 취소 등의 정리작업을 실행하기 적절합니다.
이곳에선 반드시 setState를 발생시키면 안됩니다.
componentDidCatch
자식 컴포넌트에서 에러가 발생한 경우 호출됩니다.
commit단계에서 수행되므로, 에러 처리를 통한 side effect를 일으켜도 좋습니다.
componentWillMount
컴포넌트가 DOM에 추가되기 직전에 실행되는 함수이나, 현재는