React.js Hooks 완벽 가이드: useState, useEffect 활용법

작성일 :

React.js Hooks 완벽 가이드: useState, useEffect 활용법

React는 사용자 인터페이스를 구축하기 위한 강력하고 유연한 라이브러리입니다. React에서 컴포넌트 상태를 관리하고 생명 주기 이벤트를 처리하기 위해 필요한 것이 Hooks입니다. 이 글에서는 가장 널리 사용되는 두 가지 Hook인 useStateuseEffect의 기본 개념과 활용 방법을 다루고자 합니다. 앞서 나가기에 앞서, Hooks는 함수형 컴포넌트에서 사용할 수 있습니다.

useState: 상태 관리를 위한 Hook

useState는 리액트 컴포넌트에서 상태를 관리할 때 사용하는 Hook입니다. 클래스형 컴포넌트에서는 this.statethis.setState를 사용했지만, 함수형 컴포넌트에서는 useState를 통해 상태를 설정하고 업데이트합니다. 다음은 기본적인 사용 예제입니다.

javascript
import React, { useState } from 'react';

function Counter() {
  // count라는 상태 변수와 setCount라는 상태 업데이트 함수를 선언합니다.
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>현재 카운트: {count}</p>
      <button onClick={() => setCount(count + 1)}>증가</button>
    </div>
  );
}

위 예제에서 useState(0)는 초기 상태 값을 0으로 설정합니다. useState는 두 개의 값을 반환하는데, 첫 번째 값은 현재 상태, 두 번째 값은 상태를 갱신할 수 있는 함수입니다. 상태를 갱신하기 위해서는 그 함수에 새로운 상태 값을 넘겨주면 됩니다.

상태를 여러 개 설정하기

복잡한 상태를 관리하기 위해 useState를 여러 번 호출할 수 있습니다. 예제는 다음과 같습니다.

javascript
function Profile() {
  const [name, setName] = useState('');
  const [age, setAge] = useState(0);

  return (
    <div>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="이름을 입력하세요"
      />
      <input
        type="number"
        value={age}
        onChange={(e) => setAge(Number(e.target.value))}
        placeholder="나이를 입력하세요"
      />
      <p>이름: {name}</p>
      <p>나이: {age}</p>
    </div>
  );
}

위 코드에서 우리는 nameage 두 개의 상태 변수를 설정하고 이를 각각의 입력 필드와 연결하였습니다. 상태 업데이트는 입력값의 변화에 따라 이루어집니다.

useEffect: 사이드 이펙트를 처리하는 Hook

useEffect는 컴포넌트가 렌더링된 이후에 특정 작업을 수행하기 위해 사용하는 Hook입니다. 클래스형 컴포넌트의 componentDidMount, componentDidUpdate, componentWillUnmount와 비슷한 역할을 합니다. 다음은 기본적인 사용 예제입니다.

javascript
import React, { useState, useEffect } from 'react';

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds((prevSeconds) => prevSeconds + 1);
    }, 1000);
    // 컴포넌트가 언마운트될 때 인터벌을 정리합니다.
    return () => clearInterval(interval);
  }, []); // 빈 배열은 의존성을 의미하며, 이 경우 컴포넌트가 처음 마운트될 때 한 번만 실행됩니다.

  return (
    <div>
      <p>타이머: {seconds}</p>
    </div>
  );
}

위 예제에서 useEffect는 인터벌을 설정하고 컴포넌트가 언마운트될 때 인터벌을 정리합니다. useEffect의 두 번째 인자로 빈 배열을 제공하면, 이 효과는 컴포넌트가 처음 렌더링될 때 한 번만 실행됩니다.

여러 종류의 사이드 이펙트 관리하기

useEffect를 여러 번 호출하여 다양한 사이드 이펙트를 관리할 수 있습니다. 예를 들어, API 호출과 정리 작업을 각각 분리할 수 있습니다.

javascript
import React, { useState, useEffect } from 'react';

function DataFetcher({ apiEndpoint }) {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  // 데이터 가져오기
  useEffect(() => {
    fetch(apiEndpoint)
      .then(response => response.json())
      .then(data => setData(data))
      .catch(error => setError(error));
  }, [apiEndpoint]); // apiEndpoint가 바뀔 때마다 이 효과 실행

  // 정리 작업
  useEffect(() => {
    return () => {
      console.log('컴포넌트 언마운트됨');
    };
  }, []);

  if (error) return <div>에러 발생: {error.message}</div>;
  if (!data) return <div>로딩 중...</div>;

  return (
    <div>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

위 예제에서 첫 번째 useEffect는 API 엔드포인트가 변경될 때마다 데이터를 다시 로드합니다. 두 번째 useEffect는 컴포넌트가 언마운트될 때 정리 작업(이 경우 단순히 콘솔 로그)을 수행합니다.

결론

useStateuseEffect는 리액트가 클래스형 컴포넌트의 복잡함을 줄이고 함수형 컴포넌트만으로도 충분히 복잡한 상태와 사이드 이펙트를 관리할 수 있도록 하는 강력한 도구입니다. 이 두 Hook의 적용 범위는 매우 넓으며, 리액트 애플리케이션을 더욱 효율적으로 만들기 위해 반드시 익혀야 할 기본 요소입니다.