React에는 2가지 종류의 component가 있습니다.

  1. Class Component - Component를 만들 때 class를 이용하여 만드는 방법입니다. 보통 React를 사용할 때 기본적으로 사용하는 방법입니다. Class Component를 사용하는 이유는 state와 lifecycle를 이용할 수 있다는 큰 장점 때문에 많이 사용되고 있습니다.
  2. Function Component - Function Component는 state와 lifecycle를 따로 사용할 수 없다는 단점이 있습니다. 단지 JSX return 값을 넘겨주는 용도로 사용되고 있었습니다.

React Class Component를 많이 사용하지만 여러가지 문제점들이 있습니다.

  1. Component간 상태가 있는 로직을 재활용 하기에 어려움이 있습니다.
  2. 복잡한 Component들은 이해하기에 어려움이 있습니다.
  3. 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 이벤트를 예로 보여드리겠습니다.

  1. useState는 array를 이용하여 만드는 형태입니다. state 한 개를 정할 때는 [ state명칭, setState명칭 ]를 설정한 후 useState 옆 괄호 사이에 초깃값을 입력하여 state 값을 설정합니다. 여기에서 Hooks는 이전 state와 새로운 state를 합치지 않는다는 차이점이 있습니다. 아래의 예시는 버튼 클릭을 하였는지 확인하는 Boolean state를 설정하는 예입니다.

    ...
    function App() {
      const [ buttonClicked, setButtonClicked ] = useState(false);
    }
    
  2. 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가지를 설명해 드리겠습니다.

  1. 이벤트가 발생하는 곳에서 선언
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;
  1. 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를 사용할 때 주의해야 하는 점에 대해서 말씀드리겠습니다.

  1. Hooks는 function component에서만 사용을 해야 합니다.
  2. Hooks는 최상위에서만 호출해야 합니다. 조건문, 반복문이나 중첩된 함수 내에서는 호출하면 안 됩니다.
  3. Hooks는 React Component 안에서만 호출해야 합니다. 다른 Javascript 파일 안에서 호출하면 작동이 안됩니다.
  4. 초깃값을 설정하는게 아니라면 useEffect를 사용할 때 어떤 값이 변환할 때만 rendering을 할지 설정을 해주어야 합니다. (설정하지 않으면 상황에 따라 infinite loop이 발생할 수 있습니다.)

감사합니다.

React + MobX
SPA 라이브러리인 React를 MobX state 관리 라이브러리와 함께 배워봅시다.