React에는 2가지 종류의 component가 있습니다.
- Class Component - Component를 만들 때 class를 이용하여 만드는 방법입니다. 보통 React를 사용할 때 기본적으로 사용하는 방법입니다. Class Component를 사용하는 이유는 state와 lifecycle를 이용할 수 있다는 큰 장점 때문에 많이 사용되고 있습니다.
- Function Component - Function Component는 state와 lifecycle를 따로 사용할 수 없다는 단점이 있습니다. 단지 JSX return 값을 넘겨주는 용도로 사용되고 있었습니다.
React Class Component를 많이 사용하지만 여러가지 문제점들이 있습니다.
- Component간 상태가 있는 로직을 재활용 하기에 어려움이 있습니다.
- 복잡한 Component들은 이해하기에 어려움이 있습니다.
- Class는 사람과 기계 모두에게 헷갈리는 개념입니다. 이러한 문제 해결 방안으로
Hooks
가 개발 되었습니다.
Hooks
를 이용하면 function component에서도 state와 lifecycle를 정의할 수 있는데, 정의하는 방법이 기존의 state와는 다른 형식으로 진행이 됩니다. 또한, Hooks는 function component에서만 사용할 수 있습니다. Class Component에서 Hooks를 정의하여 사용할 경우 아래와 같은 오류가 console에 나타납니다.
Hooks를 사용하려면 React 16.8버전 또는 이상
이 설치되면 사용할 수 있습니다. 첫 번째로 Hook를 사용하기 위해서는 React library에서 useState와 useEffect를 import를 하여 기본적인 설정이 필요합니다.
import React, { useState, useEffect } from 'react';
function App() {
....
}
useState
는 class component에서 사용하던 state를 function component에서 사용할 수 있도록 설정이 되어있습니다. State 정의 방식과는 약간 다르지만 state에 대해서 알고 있으면 사용할 수 있습니다. 이해를 돕기 위해 button click 이벤트를 예로 보여드리겠습니다.
-
useState는 array를 이용하여 만드는 형태입니다. state 한 개를 정할 때는
[ state명칭, setState명칭 ]
를 설정한 후 useState 옆 괄호 사이에 초깃값을 입력하여 state 값을 설정합니다. 여기에서 Hooks는 이전 state와 새로운 state를 합치지 않는다는 차이점이 있습니다. 아래의 예시는 버튼 클릭을 하였는지 확인하는 Boolean state를 설정하는 예입니다.... function App() { const [ buttonClicked, setButtonClicked ] = useState(false); }
-
state를 하나씩 설정 할때에는 위와 같은 예시로 만들 수 있습니다. 하지만 여러 개의 state가 필요 할 때에는 state 한 개를 설정 한 후, useState에 여러 개의 state 초깃값을 입력하여 한 번에 처리할 수 있도록 설정하면 사용 가능합니다.
... function App() { const [ state, setState ] = useState({ buttonClicked: false, name: '' }) }
위와 같은 방법으로 state와 setState를 선언할 수 있습니다. Hooks에서는 state를 선언하는 방식과 같게 props 또한 선언을 render 함수 안에서 할 수 있습니다.
...
function App(props) {
const [ buttonClicked, setButtonClicked ] = useState(props.buttonClicked);
}
이번에는 setState를 활용하는 방법 2가지를 설명해 드리겠습니다.
- 이벤트가 발생하는 곳에서 선언
function App() {
const [ buttonClicked, setButtonClicked ] = useState(false);
return(
<div className="App">
<p> button clicked: {buttonClicked}</p>
<button onClick={() => setButtonClicked(true)}> True Click! </button>
<button onClick={() => setButtonClicked(false)}> False Click! </button>
</div>
)
}
export default App;
- function으로 선언한 다음에 return 부분에서 호출만 하여 활용하는 방법
...
function App() {
const [ buttonClicked, setButtonClicked ] = useState(false);
function setTrue() {
setButtonClicked(true)
}
function setFalse() {
setButtonClicked(false)
}
return (
<div className="App">
<p> button clicked: {buttonClicked} </p>
<button onClick={setTrue}> True Click! </button>
<button onClick={setFalse}> False Click! </button>
</div>
)
}
export default App;
이처럼 state와 props를 Hook의 useState를 이용하여 간단하게 state 선언과 setState와 같이 state의 변환하는 값을 보일 수 있습니다. 이번에는 useEffect를 이용하여 lifecycle도 Hooks에서 적용하는 방법을 배워보겠습니다. Class Component에서는 lifecycle를 여러 가지 함수로 사용해서 적용 시킬 수 있었습니다. 예를 들어 componentDidMount, componentDidUpdate, etc. 와 같이 다양하게 함수명을 선언해야지 해당 상황에서 적용되지만, Hooks에서는 useEffect 하나로 모든 lifecycle 변화가 적용됩니다.
기본적으로 useEffect 사용 방법에 대해 예를 통해 보여드리겠습니다.
...
function App() {
useEffect(() => {
doingSomething()
},[])
}
...
위의 예시와 같이 useEffect를 사용하면 우리가 Component Class에서 사용하던 lifecycle method 중 componentDidMount와 같아 초깃값 설정에 필요한 작업을 설정해줄 수 있습니다. [] <- 해당 부분은 componentDidMount에서 해주었던 방식과 같게 렌더링을 한 번만 하고 나서 그 이후에는 다시 사용되지 않는 초기화 값입니다. 그렇다면 state 또는 props의 변화를 감지하여 자동으로 업데이트를 해주던 componentDidUpdate의 설정을 하는 방법에 대해서 알려드리겠습니다.
...
function App() {
useEffect(() => {
doingSomethingWhenButtonClickedChange()
}, [buttonClicked])
}
...
위의 예시와 같이 변화되는 걸 감지할 값은 [] 안에 입력하시면 해당 값이 변화될 때마다 업데이트가 진행됩니다. 그래서 useEffect를 이용하면 lifecycle의 직접 변화를 감지하고 처리해 줄 수 있습니다. 처음에는 헷갈릴 수도 있지만 간단하게 생각을 하여 사용을 하면 lifecycle methods보다 더욱더 간편하고 다양하게 활용할 수 있는 장점이 있습니다.
그리고 useEffect를 사용할 때 항상 []을 설정을 해주셔야 infinite loop 현상이 발생하지 않으면서 정상적으로 작동할 수 있습니다. 초기화 이외의 lifecycle의 변화를 주려면 항상 어떤 값이 변화할 때 해당 lifecycle를 적용 시킬 예정인지 선언해주어야 합니다.
Hooks를 사용할 때 주의해야 하는 점에 대해서 말씀드리겠습니다.
- Hooks는 function component에서만 사용을 해야 합니다.
- Hooks는 최상위에서만 호출해야 합니다. 조건문, 반복문이나 중첩된 함수 내에서는 호출하면 안 됩니다.
- Hooks는 React Component 안에서만 호출해야 합니다. 다른 Javascript 파일 안에서 호출하면 작동이 안됩니다.
- 초깃값을 설정하는게 아니라면 useEffect를 사용할 때 어떤 값이 변환할 때만 rendering을 할지 설정을 해주어야 합니다. (설정하지 않으면 상황에 따라 infinite loop이 발생할 수 있습니다.)
감사합니다.