LifeCycle과 Hook이란
LifeCycle
이란 컴포넌트의 생명주기를 뜻하고, 이 메서드를 오버라이딩해서
특정 시점에 코드가 실행되도록 설정할 수 있습니다.
Hook
은 React 버전 16.8에서 추가되었고
class
를 사용하지 않고 생명주기를 사용할 수 있게 해줍니다. 이 생명주기를 잘 사용한다면 빠르고 최적화된 웹 페이지를 경험할 수 있습니다.
LifeCycle
constructor()
constructor(props) {
super(props)
this.state = {
count: 0
}
}
React 컴포넌트의 생성자는 해당 컴포넌트가 생성되기 전에 실행됩니다. 이 메서드를 구현할 때
super(props)
를 해주어야 합니다. 그렇지 않으면 this.props
가 생성자 내에서 정의되지 않아 에러가 날 수 있습니다. 생성자를
사용하는 이유는 this.state
에 객체를 할당하여 state
를 초기화하거나 인스턴스에 이벤트 처리를 위해 사용됩니다.
render()
render() {
return (
<div class="App">
</div>
)
}
render()
는 클래스 컴포넌트에서 반드시 구현되어야 하는 메서드입니다. 이
메서드는 주로 React Element인 JSX
를 반환합니다. return test && <CustomElement />
패턴을 지원합니다. test
가 true
라면 CustomElement
를 반환하고 그렇지 않다면
null
을 반환합니다.
componentDidMount()
componentDidMount() {
}
이 메서드는 컴포넌트가 DOM에 삽입된 직후 호출됩니다. DOM노드가 필요한 초기화 작업을 수행하기
좋고, 네트워크 요청을 보내기도 적절합니다. 이 메서드에서 setState()
를 호출하는 경우도 있습니다. 추가적인 렌더링이 발생하지만 화면을 갱신하기 전에 이루어집니다.
componentDidUpdate()
componentDidUpdate(prevProps, prevState, snapshot) {
}
componentDidUpdate()
는 갱신이 일어난 직후 호출됩니다. 최초
렌더링에서는 호출되지 않습니다. 컴포넌트가 갱신되었을 때 DOM을 조작하기 위해 사용됩니다. 이전과 현재의 props
를 비교하여 네트워크 요청을 보내는 작업도 좋습니다.
// 예시
componentDidUpdate(prevProps) {
if(this.props.userID !== prevProps.userID) { // 이전과 현재의 userID과 다르다면
this.fetchData(this.props.userID)
}
}
이 메서드에서 setState()
를 사용할 수 있지만 조건문으로 감싸지 않으면
무한반복이 일어날 수 있습니다. 또한 추가적인 렌더링이 발생할 수 있습니다.
componentWillUnmount()
componentWillUnmount() {
}
componentWillUnmount()
는 컴포넌트가 제거되기 전에 호출됩니다.
이 메서드에서는 타이머 제거, 네트워크 요청 취소 등의 작업을 하기 적당합니다.
Hook
useState()
import React, { useState } from "react";
function example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
위의 코드는 React Hook 공식문서에 나와있는 카운터 예제입니다.
useState()
는 React의 State Hook으로 state
와 값을 업데이트하는 함수를 제공합니다. 이
state
는 컴포넌트가 다시 렌더링되어도 값을 유지합니다. useState()
는 인자로 초기값을 받습니다. 카운터는 0부터 시작하기 때문에
예제에서는 0을 초기값으로 넣어주었습니다. 그리고 useState()
는 여러 개의 state
를 만들 수 있습니다.
import React, { useState } from "react";
function example() {
// 여러 state 선언
const [name, setName] = useState("John");
const [age, setAge] = useState(18);
const [favorite, setFavorite] = useState({ fruit: "apple" });
}
useEffect()
컴포넌트 안에서 데이터를 가져오거나 구독하고, DOM을 직접 조작하는 것을
side effects
, 줄여서 effects
라고 합니다. useEffect()
는 effects
를
수행할 수 있게 하는 Effect Hook입니다.
import React, { useState, useEffect } from "react";
function example() {
const [count, setCount] = useState(0);
// componentDidMount, componentDidUpdate와 유사
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
위의 예제는 React Hook 공식 문서의 useEffect()
를
사용한 예제입니다. 이 컴포넌트가 업데이트되었다면 타이틀을 카운트로 바꾸어줍니다. useEffect()
는 deps
(의존성)을 사용하여 조건적으로
다시 렌더링을 시킬 수 있습니다.
import React, { useState, useEffect } from "react";
function example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
위와 같이 useEffect()
의 두 번째 인자로
deps
를 넣어주게 되면 해당 변수가 업데이트될 때 함수를 실행하게 됩니다. 하지만 deps
에 아무 변수도 넣지 않는다면 컴포넌트가 다시 렌더링될
때마다 실행되고 빈배열을 넘긴다면 최초 렌더링 시에만 함수를 실행하고 그 후로는 실행되지 않습니다. 또한 useEffect()
에서 함수를 반환할 수 있는데
deps
가 비어있는 경우 컴포넌트가 사라질 때 실행되는 함수입니다.
import React, { useState, useEffect } from 'react';
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
컴포넌트가 마운트가 해지될 때 ChatAPI가 구독을 해지할 것입니다. 또한
useState()
와 마찬가지로 여러 개의 effect
를 생성할 수 있습니다.
import React, { useState, useEffect } from 'react';
function FriendStatusWithCounter(props) {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
}