컴포넌트 업데이트 전후로 처리해야 할 때 사용하는 컴포넌트의 라이프사이클 메서드를 알아보자.
알고 넘어가자!
- 라이프사이클 메서드는 클래스형 컴포넌트에서만 사용할 수 있음.
- 대신 함수 컴포넌트는 Hooks 기능을 사용하여 비슷하게 작업을 처리할 수 있음.
💡 라이프사이클 메서드의 이해
- 라이프사이클 메서드는 컴포넌트 상태에 변화가 있을 때마다 실행하는 메서드임.
- 서드파티 라이브러리를 사용하거나 DOM을 직접 건드려야 하는 상황에서 유용함.
shouldComponentUpdate
로 컴포넌트의 업데이트 성능을 개선할 수 있음.

constructor
: 컴포넌트를 새로 만들 때마다 호출되는 클래스 생성자 메서드.
getDerivedStateFromProps
: props에 있는 값을 state에 넣을 때 사용하는 메서드.
static getDerivedStateFromProps(nextProps, prevState) { if(nextProps.value !== prevState.value) { return { value: nextProps.value }; } return null; }
render
: 컴포넌트를 렌더링 함.
componentDidMount
: 컴포넌트가 웹 브라우저 상에 나타난 후(업데이트 작업이 끝난 후) 호출하는 메서드. 이 안에서 함수 호출, 이벤트 등록, 비동기 네트워크 요청같은 작업을 처리함.
shouldComponentUpdate
: 컴포넌트가 리렌더링을 할지 말지를 결정하는 메서드. true 또는 false 값을 반환함.
getSnapshotBeforeUpdate
: 컴포넌트 변화를 DOM에 반영하기 바로 직전에 호출하는 메서드.
//ex 스크롤바 위치 유지 getSnapshotBeforeUpdate(prevProps, prevState) { if(prevState.array !== this.state.array) { const { scrollTop, scrollHeight } = this.list return { scrollTop, scrollHeight }; } }
componentWillUnmount
: 컴포넌트가 웹 브라우저 상에서 사라지기 전에 호출하는 메서드. 컴포넌트를 DOM에서 제거할 때 실행.
componentDidUpdate
: 리렌더링 완료 후 실행. DOM 관련 처리 가능. prevProps 또는 prevState를 사용하여 컴포넌트가 이전에 가졌던 데이터에 접근할 수 있음.
componentDidCatch
: 컴포넌트 렌더링 도중 에러가 발생했을 때 애플리케이션이 먹통이 되지 않고 오류 UI를 보여줄 수 있게 해줌.
componentDidCatch(error, info) { this.setState({ error: true }); console.log({ error, info }); }
정리
- 라이프사이클 메서드는 총 9가지.
Will
접두사가 붙은 메서드는 어떤 작업을 작동하기 전 실행되는 메서드.Did
접두사가 붙은 메서드는 어떤 작업을 작동한 후에 실행하는 메서드.
- 라이프사이클은 총 3가지.
- Mount : DOM이 생성되고 브라우저 상에 나타나는 것.
constructor
,getDerivedStateFromProps
,render
,componentDidMount
- Update : 4 가지 경우에 업데이트.
- props가 바뀔 때.
- state가 바뀔 때.
- 부모 컴포넌트가 리렌더링될 때.
- this.forceUpdate로 강제로 렌더링을 트리거할 때.
- Unmount : 컴포넌트를 DOM에서 제거.
componentWillUnmount
getDerivedStateFromProps
, shouldComponentUpdate
, render
, getSnapshotBeforeUpdate
, componentDidUpdate
✨ Hooks으로 더욱 강력해지다
- 리액트에서 Hooks 패턴을 사용하면 클래스형 컴포넌트를 작성하지 않고도 대부분의 기능을 구현할 수 있음.
- 프로젝트 개발 시 함수 컴포넌트의 사용을 첫 번째 옵션으로 두고, 꼭 필요한 상황에서만 클래스형 컴포넌트를 구현하는 게 좋음.
useState
- 가변적인 상태를 지닐 수 있게 함.
useEffect
- 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있음.
- 클래스형 컴포넌트의
compoentDidMount
,componentDidUpdate
를 합친 형태로 봐도 됨.
- 마운트될 때만 실행하고 싶다면 함수의 두 번째 파라미터로 비어 있는 배열을 넣어주면 됨.
componentDidUpdate
처럼 특정 값이 변경될 때만 호출하고 싶을 때 배열 안에 검사하고 싶은 값을 넣어주면 됨.
static getDerivedStateFromProps(prevProps, prevState) { if(prevProps.value !== prevState.value) { doSomething(); } return null; }
useEffect(()=> { console.log(name); }, [name]);
- 컴포넌트가 언마운트되기 전이나 업데이트되기 직전에 어떠한 작업을 수행하고 싶다면 return할 때 함수를 실행해야 함.
useEffect(()=> { console.log(name); return () => { console.log(name); } }, [name]);
useRef
useRef
를 사용하여 ref를 설정하면 만든 객체 안의 current 값이 실제 요소를 가리킴.
UI 컴포넌트에서
useRef
를 사용할 수 없음. 그 대신 forwardRef
사용.useReducer
- useState보다 더 다양한 컴포넌트 상황에 따라 다양한 상태를 다른 값으로 업데이트 해주고 싶을 때 사용하는 Hook.
- reducer는 현재 상태, 그리고 업데이트를 위해 필요한 정보를 담은 action 값을 전달받아 새로운 상태를 반환하는 함수.
- 컴포넌트 업데이트 로직을 바깥으로 빼낼 수 있다는 장점이 있음.
import React, { useReducer } from 'react'; function reducer(state, action) { // action.type 에 따라 다른 작업 수행 switch (action.type) { case 'INCREMENT': return { value: state.value + 1 }; case 'DECREMENT': return { value: state.value - 1 }; default: // 아무것도 해당되지 않을 때 기존 상태 반환 return state; } } const Counter = () => { const [state, dispatch] = useReducer(reducer, { value: 0 }); return ( <div> <p> 현재 카운터 값은 <b>{state.value}</b> 입니다. </p> <button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button> <button onClick={() => dispatch({ type: 'DECREMENT' })}>-1</button> </div> ); }; export default Counter;
useMemo
- 함수 컴포넌트 내부에서 발생하는 연산 최적화.
useCallback
- useMemo와 비슷하게 렌더링 성능을 최적화해야 하는 상황에서 사용.
- 만들었던 함수 재사용.
- 컴포넌트의 렌더링이 자주 발생하거나 렌더링해야 할 컴포넌트의 개수가 많아지면 최적화해주는 것이 좋음.
모든 추상화 및 최적화 코드에는 비용이 들기 때문에 발생하는 비용을 상쇄 시킬만한 비용절약이 있지 않으면 오히려 비용 증가가 일어남.
커스텀 Hooks
- 여러 컴포넌트에서 비슷한 기능을 공유할 경우, 커스텀 Hook을 작성하여 로직을 재사용할 수 있음.
참고자료 :
리액트를 다루는 기술 7장