Gapus Dev Blog

[React] 훅(Hook)에 대해 본문

프론트엔드/React

[React] 훅(Hook)에 대해

Gapus 2023. 11. 30. 08:00

훅(Hook)

 

설명

 

  • 함수형 컴포넌트에서 상태(state)와 생명주기 메서드(lifecycle method)를 사용할 수 있게 해주는 기능
  • 클래스형 컴포넌트에서만 상태를 관리하고 생명주기 메서드를 사용할 수 있었지만, 훅을 이용하면 함수형 컴포넌트에서도 동일한 기능을 사용 가능
  • 함수형 컴포넌트 내에서만 사용 가능하며, 훅의 호출 순서는 항상 동일해야 한다.
  • 규칙을 지키면서 훅을 적절하게 사용하면 상태 관리와 생명주기 처리를 간편하게 가능

 


 

훅(Hook)의 종류

 

useState

 

  • 상태를 관리하는데 사용되는 훅
  • 함수형 컴포넌트 내에서 상태를 생성하고 업데이트를 가능
  • 예를 들어, 숫자나 문자열과 같은 값을 저장하고 업데이트 가능
  • 예시
import React, { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

export default Counter;

 

 

useEffect

 

  • 생명주기 메서드와 비슷한 역할을 수행하는 훅
  • 컴포넌트가 렌더링될 때마다 실행되는 코드를 작성하거나, 특정 상태가 변경될 때 실행되는 코드를 작성 가능
  • 이를 통해, 비동기 작업이나 데이터 가져오기, 이벤트 등을 처리 가능
  • 예시
import React, { useEffect, useState } from 'react';

const DataFetcher = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    // 데이터 가져오기
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => setData(data));
  }, []);

  return (
    <div>
      <ul>
        {data.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default DataFetcher;

 

 

useContext

 

  • 리액트의 Context API와 함께 사용되는 훅
  • 이 훅을 사용하면 컴포넌트 간에 상태를 공유 가능
  • 하위 컴포넌트에서 상위 컴포넌트로 데이터를 전달할 때 유용하게 사용 가능
  • 예시
import React, { useContext } from 'react';

const ThemeContext = React.createContext('light');

const ThemeComponent = () => {
  const theme = useContext(ThemeContext);

  return <div>Current theme: {theme}</div>;
};

export default ThemeComponent;

 

 

useReducer

 

  • 복잡한 상태 관리를 위해 사용되는 훅
  • useState와 달리 상태를 업데이트하는 로직을 별도의 함수로 분리하여 처리 가능
  • 이를 통해, 상태 업데이트 로직을 더욱 명확하게 작성 가능
  • 예시
import React, { useReducer } from 'react';

const initialState = { count: 0 };

const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
};

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, initialState);

  const increment = () => {
    dispatch({ type: 'increment' });
  };

  const decrement = () => {
    dispatch({ type: 'decrement' });
  };

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

export default Counter;

 

 

useRef

 

  • DOM 요소에 접근하거나 컴포넌트 내에서 변수를 유지할 때 사용되는 훅
  • 이 훅을 사용하면 컴포넌트가 리렌더링되어도 변수의 값이 유지
  • 예시
import React, { useRef } from 'react';

const InputField = () => {
  const inputRef = useRef(null);

  const handleButtonClick = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={handleButtonClick}>Focus Input</button>
    </div>
  );
};

export default InputField;

 

 

useMemo

 

  • 계산 비용이 많이 드는 함수의 결과 값을 저장하고 재사용할 때 사용되는 훅
  • 이를 통해, 성능을 최적화 가능
  • 예시
import React, { useMemo } from 'react';

const ExpensiveCalculation = () => {
  const expensiveResult = useMemo(() => {
    // 복잡한 계산 로직
    let result = 0;
    for (let i = 0; i < 1000000; i++) {
      result += i;
    }
    return result;
  }, []);

  return <div>Result: {expensiveResult}</div>;
};

export default ExpensiveCalculation;

 

 

useCallback

 

  • 함수를 메모이제이션하여 재사용할 때 사용되는 훅
  • 의존성 배열이 변경되지 않는 한 이전에 생성된 함수를 반환
  • 예시
import React, { useCallback, useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []);

  const decrement = useCallback(() => {
    setCount(prevCount => prevCount - 1);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

export default Counter;

 

 

custom hooks

 

  • 개발자가 직접 만든 커스텀 훅
  • 특정한 로직을 재사용하기 위해 만들어진 훅으로, 기능에 따라 다양한 커스텀 훅을 만들 수 있다.
  • 예시
import React from 'react';

const useCustomHook = () => {
  // 커스텀 훅 로직 작성
  // 여기서는 간단히 현재 시간을 반환하는 예시를 보여줍니다.
  const getCurrentTime = () => {
    const currentTime = new Date().toLocaleTimeString();
    return currentTime;
  };

  return getCurrentTime;
};

const Timer = () => {
  const getCurrentTime = useCustomHook();

  return (
    <div>
      <p>Current Time: {getCurrentTime()}</p>
    </div>
  );
};

export default Timer;

 

 


 

훅 사용할 때 장점

 

간결한 코드

 

  • 훅을 사용하면 함수형 컴포넌트에서 상태 관리와 생명주기 처리를 간결하게 가능
  • 클래스형 컴포넌트에서의 복잡한 구조와 메서드를 사용하지 않아도 되므로 코드가 간결 해짐

 

상태 관리의 용이성

 

  • useState 훅을 사용하면 함수형 컴포넌트 내에서도 상태를 생성하고 업데이트 가능
  • 이를 통해, 상태관리가 훨씬 간편해지고, 클래스형 컴포넌트에서의 this.setState를 사용하지 않아도 된다.

 

생명주기 메서드 대체

 

  • useEffect 훅을 사용하면 컴포넌트의 생명주기 메서드를 대체 가능
  • 컴포넌트가 렌더링될 때마다 실행되는 코드나 특정 상태가 변경될 때 실행되는 코드를 작성 가능

 

재사용 가능한 로직

 

  • 커스텀 훅을 만들어 재사용 가능한 로직을 구성 가능
  • 특정한 기능을 수행하는 로직을 훅으로 추상화하고, 다른 컴포넌트에서 해당 훅을 호출하여 재사용 가능

 

성능 최적화

 

  • useMemo와 useCallback 훅을 사용하여 계산 비용이 많이 드는 함수나 의존성이 변경되지 않는 함수를 메모이제이션하여 성능을 최적화 가능
  • 불필요한 렌더링을 방지하고 성능을 향상 가능

 

클래스 컴포넌트와의 호환성

 

  • 훅은 함수형 컴포넌트에서 사용되므로 클래스형 컴포넌트와 비교하여 훨씬 간단하고 직관적인 구조를 가짐
  • 기존에 클래스형 컴포넌트를 사용하던 개발자들도 쉽게 훅을 사용 가능