React의 생명주기(lifecycle)는 크게 세 가지 단계로 나눌 수 있습니다. 바로 마운팅(mounting), 업데이트(updating), 그리고 언마운팅(unmounting)입니다. 마운팅은 React 컴포넌트가 DOM(Document Object Model, 문서 객체 모델)에 렌더링되는 시점을 의미하며, 이후 컴포넌트에 변화가 일어나면 업데이트 단계로 넘어갑니다.
업데이트 단계에서는 내부적으로 일련의 메서드들이 실행되어 새로운 정보를 확인하고 해당 컴포넌트를 다시 렌더링합니다. 언마운팅은 말 그대로 컴포넌트가 DOM에서 제거되는 과정입니다.
이 글에서는 생명주기의 전반적인 개념과 자주 사용되는 메서드들을 살펴봅니다. 실제로 활용할 수 있는 생명주기 메서드는 이보다 훨씬 많지만, 여기서는 핵심 위주로 다룹니다. 나머지 메서드에 대한 자세한 내용은 공식 React 문서를 참고하시기 바랍니다.
React 생명주기란 무엇인가?
컴포넌트가 DOM에 로드되면 세 가지 단계 중 첫 번째 단계, 즉 마운팅 단계에 진입합니다. 이 단계에서 컴포넌트는 처음 정의된 그대로 렌더링되며, 사용자와 상호작용할 준비를 마친 뒤 두 번째 단계로 넘어갑니다.
두 번째 단계에서는 사용자가 컴포넌트와 상호작용하면서 변화가 발생합니다. 대부분의 경우 사용자가 수행한 동작이 컴포넌트의 state를 변경하게 되는데, 이때 우리는 생명주기의 업데이트 단계에 들어선 것입니다.
업데이트 단계에서 React는 컴포넌트를 다시 렌더링하여 변경 사항을 화면에 반영합니다. 앞서 state 변경으로 업데이트 단계를 트리거하는 경우를 예로 들었는데, 이때 setState() 메서드가 호출되어 초기 state를 변경하고 재렌더링 프로세스를 시작합니다.
마지막으로 특정 컴포넌트에서 벗어나 페이지를 이동할 때, 해당 컴포넌트를 DOM에서 제거할 수 있습니다. 이를 언마운팅이라 하며, 생명주기의 세 번째 단계입니다. 필수는 아니지만, 컴포넌트가 많은 애플리케이션에서는 성능을 위해 적용하는 것이 좋습니다.
주요 생명주기 메서드
React 컴포넌트의 생명주기 흐름을 살펴보았으니, 이제 자주 사용되는 생명주기 메서드들을 알아보겠습니다. 생명주기 메서드란 각 생명주기 단계에서 호출되는 React 메서드를 의미하며, 필수인 것과 선택적인 것이 있습니다. 여기서는 필수 메서드와 널리 쓰이는 선택적 메서드들을 중심으로 설명합니다.
마운팅(Mounting)
클래스 컴포넌트를 마운팅할 때 가장 먼저 등장하는 선택적 메서드는 constructor()입니다. constructor 메서드 안에서 컴포넌트의 초기 state를 직접 선언할 수 있습니다.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
currentUser: " "
}
}
}
이 예제에서는 현재 사용자(currentUser)를 나타내는 초기 state를 객체 형태로 설정했습니다. constructor() 메서드에는 반드시 super() 메서드를 호출해야 한다는 점도 기억하세요.
여기서는 아직 아무도 로그인하지 않은 상태라고 가정해 보겠습니다. 사용자가 로그인하려면 로그인 폼이 필요한데, 이때 첫 번째 필수 메서드인 render()가 등장합니다.
컴포넌트 마운팅에 반드시 필요한 메서드가 바로 render()입니다. 클래스 컴포넌트가 초기 state와 함께 생성된 후, render()를 통해 다른 컴포넌트나 HTML을 렌더링할 수 있습니다.
render() {
return (
<LoginForm />
)
}
render()의 return 문은 다른 메서드들과 문법이 조금 다릅니다. 중괄호 {}가 아닌 소괄호 ()를 사용한다는 점에 유의하세요. 위 코드에서는 return 문 안에서 LoginForm 컴포넌트를 렌더링하고 있습니다.
사용자가 로그인하면 자격 증명(credentials)에 접근할 수 있게 됩니다. 실제 애플리케이션에서는 서버에 fetch 요청을 보내 일치하는 자격 증명을 받아오지만, 이 입문 글에서는 설명의 편의를 위해 state를 직접 설정하겠습니다.
간단한 예로, John이라는 사용자가 있다고 해봅시다. John이 비밀번호를 입력하고 로그인 버튼을 누르면 서버로 fetch 요청이 전송되고, 서버는 John의 자격 증명으로 응답합니다. 이제 John이 스스로 로그아웃을 결정할 때까지 로그인 상태를 유지하고 싶습니다.
이를 위해 자주 사용되는 또 다른 선택적 메서드인 componentWillMount()를 활용할 수 있습니다. 이 생명주기 메서드는 컴포넌트가 마운트되기 직전, 즉 첫 렌더링이 일어나기 전에 실행되므로 새로운 state를 설정하기 좋은 위치입니다.
componentWillMount() {
this.setState({
currentUser: "John"
})
}
참고:componentWillMount()는 React 16.3부터 지원 중단(deprecated)되었으며, 현재는UNSAFE_componentWillMount라는 이름으로만 사용할 수 있습니다. 최신 React에서는componentDidMount()나getDerivedStateFromProps()를 사용하는 것이 권장됩니다.
이렇게 하면 컴포넌트가 렌더링되면서 state에 현재 사용자가 John으로 설정됩니다. setState() 메서드를 호출하면 React에게 컴포넌트에 변화가 있음을 알려주고, React는 이를 반영하기 위해 컴포넌트를 다시 렌더링합니다. 결과적으로 화면에는 John이 로그인된 상태가 표시됩니다.
업데이트(Updating)
생명주기의 업데이트 단계에는 이 입문 글의 범위를 넘어서는 다양한 선택적 생명주기 메서드들이 존재합니다. 여기서 기억할 핵심은, 변화가 감지되면(일반적으로 setState() 호출을 통해) React가 필수 메서드인 render()를 다시 호출한다는 점입니다. 그러면 컴포넌트가 재렌더링되면서 변경 사항이 화면에 그대로 반영됩니다.
언마운팅(Unmounting)
컴포넌트 생명주기의 마지막 단계는 언마운팅입니다. 이 단계에서 컴포넌트는 DOM에서 제거됩니다. 필수는 아니지만, 컴포넌트가 많은 애플리케이션의 성능 최적화에 큰 도움이 됩니다.
언마운팅에는 단 하나의 선택적 메서드 componentWillUnmount()만 있습니다. 이제 John이 로그아웃하려 한다고 해봅시다. 로그아웃 버튼을 클릭하면 componentWillUnmount()를 사용해 그의 사용자 프로필을 DOM에서 제거할 수 있습니다.
다소 인위적인 예시이지만, 생명주기의 각 단계에서 어떤 일이 일어나는지 명확하게 보여줍니다.
class UserContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
currentUser: " "
}
}
componentWillMount() {
this.setState({
currentUser: "John"
})
}
logout = () => {
this.setState({
currentUser: " "
})
}
render() {
if (this.state.currentUser === "John") {
return (
<div>
<UserProfile />
<button type="button" onClick={this.logout}>Logout</button>
</div>
)
} else {
return (
<button type="button">Login</button>
)
}
}
}
class UserProfile extends React.Component {
componentWillUnmount() {
alert("Logged Out")
}
render() {
return (
<h1>Welcome back, John!</h1>
)
}
}
여기에는 두 개의 컴포넌트가 있습니다. 첫 번째는 UserContainer로, UserProfile 컴포넌트를 담고 있는 역할을 합니다. UserProfile에는 사용자 정보가 담겨 있습니다.
UserContainer에서는 앞서와 같이 컴포넌트를 생성하고 초기 state를 설정합니다. 컴포넌트는 잠시 로그인 버튼과 함께 렌더링되고, 곧이어 마운트되기 직전에 John이 로그인됩니다. 이로 인해 React는 컴포넌트를 업데이트하여 John의 정보와 함께 다시 렌더링합니다.
John이 로그인하면 UserProfile 컴포넌트가 렌더링됩니다. 이 컴포넌트에는 John의 모든 사용자 정보가 포함되어 있으므로, 로그아웃하는 즉시 DOM에서 제거해야 합니다.
로그아웃 버튼을 클릭하면 logout 함수가 실행되어 현재 사용자를 빈 문자열이라는 초기 상태로 되돌립니다. logout 함수가 setState를 호출하기 때문에 React는 컨테이너 컴포넌트를 다시 렌더링합니다. 그러면 화면에서 UserProfile 컴포넌트가 사라지고, 사용자에게 로그아웃되었다는 알림 팝업이 표시됩니다.
결론
React 생명주기에는 이 글에서 다룬 내용 외에도 알아야 할 것이 많습니다. 이 글의 목표는 간단한 코드 예제와 함께 기본 개념을 소개하는 것이었습니다. 생명주기 개념을 익혔다면, 이제 공식 React 문서를 읽을 때 훨씬 수월하게 이해할 수 있을 것입니다.
이 가이드를 끝까지 읽고 나면 React 생명주기가 무엇인지 확실히 파악했을 뿐만 아니라, 스스로 더 깊이 학습해 나갈 수 있는 탄탄한 기반을 갖추게 됩니다. 프로그래밍의 모든 복잡한 개념이 그렇듯, 매일의 꾸준한 연습이 세부 사항을 익히는 데 가장 큰 도움이 됩니다.