React를 공부하다 보면 Hooks라는 말을 자주 접하게 된다.
그래서 Hooks에 대해 공부해 보고자 한다.
React Hook은 React 16.8 버전에서 새롭게 추가된 리액트 라이브러리 사용방법이다. 기존에 클래스를 통해 컴포넌트의 state를 관리하였는데, Hook를 통해 함수형 컴포넌트에서도 스테이트를 관리할 수 있게 되었다는게 가장 큰 특징이다.
따라서 리액트의 작성방법은 두 가지가 존재하고 있으며, 그게 위에서 말한 Class Component(클래스 컴포넌트) & Function Component(함수 컴포넌트)!
클래스 컴포넌트에는 상태관리나 라이프사이클의 기능이 있지만, 함수 컴포넌트에는 그 기능이 없었다.
하지만 Hook이 생기면서 함수 컴포넌트에서도 State를 이용하여 상태관리나 라이프사이클 함수를 사용하는 것이 가능졌다!🥳
아래 코드는 React 공식문서의 예제 코드이다. 클래스 컴포넌트와 함수 컴포넌트에서 어떻게 상태관리를 할 수 있는지 알 수 있다.
// Function component(Hook)
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>
);
}
// Class component
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
한 눈에 봐도 코드의 양은 물론, 훨씬 읽기 쉬워졌다. 이는 코드 재이용성이 높아지고 테스트 코드를 작성하기 쉽다는 것으로 이어질 수 있다.
기본적으로 제공되지만 가장 중요한 useState, useEffect에 대해 알아보도록 하겠다.
useState
가장 대표적인 Hook이다. 클래스 컴포넌트에 의지하지 않고 state를 가질 수 있게 해준다.
위에서 본 예제 코드를 다시 한 번 보도록 하겠다.
useState()라는 함수는 배열을 리턴하도록 되어있다. 따라서 아래 코드와 같이 ES6의 Destructuring assignment 방식으로 할당할 수 있으며, 첫 번째 count는 스테이트의 값, 두 번째 setState는 스테이트를 변경하는 함수이다.
또한 useState() 인수로 값을 넣어 기본값을 줄 수 있다.
따라서 아래 코드에서는 count의 기본값이 0이 되며, 버튼을 클릭하면 count의 값이 1씩 증가하게 되는 구조이다.
import React, { useState } from 'react';
function Example() {
// Hook은 반드시 컴포넌트의 최상위에서 호출해야 한다.!
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useEffect
useEffect는 라이프사이클 함수와 관련이 있다. 기존 클래스 컴포넌트에서는 다양한 종류의 라이프사이클 함수가 존재하여(componenetDidMount 등) 렌더링의 순서나 기능의 용도에 맞게 라이프사이클 함수를 사용해야 한다.
기능이 복잡해 지면 다소 복잡하며 번거로운 작업이 되기도 하는데, useEffect Hook은 이를 더욱 간결하게 사용할 수 있게 되었다.
기본적으로 렌더링이 이루어질 때 마다 작동하지만, 두 번째 인수의 배열을 통해 특정 스테이트가 변화할 때만 작동하도록 하는 것도 가능하다.
기본적으로 처음 컴포넌트가 마운트가 될 때, 한 번 작동하게 되고(componentDidMount), 두 번째 인수가 주어지지 않는다면 스테이트가 변화할 때 마다, 렌더링이 다시 이루어진다.(componentDidUpdate).
그리고 useEffect() 함수 내에서 리턴을 통해 componentWillUnmount 라이프사이클도 사용할 수 있다.
결국 useEffect() 함수는 componentDidMount, componentDidUpdate, componentWillUnmount 라이프사이클이 합쳐져 있다고 볼 수 있다.
아래 예제 코드는 두 번쨰 인수가 주어지지 않았기 때문에, componentDidMount, componentDidUpdate의 라이프사이클이 사용되고 있다고 볼 수 있다. 따라서 count의 스테이트가 변경될 때 마다 새롭게 렌더링이 이루어지게 된다.
// useEffect Hook
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
// Class component
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}