실무에서 활용되는 리액트 Hooks 사용 방법

1. 리액트 Hooks 개요

리액트 Hooks는 함수형 컴포넌트에서 상태 관리와 사이드 이펙트 처리를 간편하게 할 수 있는 기능입니다. 이전에는 클래스형 컴포넌트에서만 상태와 라이프사이클 메소드를 다룰 수 있었지만, Hooks를 사용하면 함수형 컴포넌트에서도 같은 기능을 사용할 수 있습니다.

Hooks는 useState, useEffect, useContext 등 다양한 API를 제공하며, 개발자가 컴포넌트 로직을 더 쉽게 작성하고 이해할 수 있도록 도와줍니다.

1.1 useState Hook 사용 방법

useState Hook을 사용하면 함수형 컴포넌트 내에서 상태 값을 저장하고 변경할 수 있습니다.

import React, { useState } from 'react';

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

  return (
    

Count: {count}

); } export default Counter;

이 예시에서는 useState Hook을 사용하여 count라는 상태 값을 정의하고, setCount 함수를 통해 상태 값을 변경합니다. 버튼을 클릭할 때마다 count가 1씩 증가하고, 화면에 보여지는 값이 업데이트됩니다.


2. useState Hook 사용 방법

useState Hook을 사용하면 함수형 컴포넌트에서 상태 값을 저장하고 변경할 수 있습니다.

2.1 기본 사용 방법

import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  return (
    

Count: {count}

); } export default Example;

이 예시에서는 useState Hook을 사용하여 count라는 상태 값을 정의하고, setCount 함수를 통해 상태 값을 변경합니다. 버튼을 클릭할 때마다 count가 1씩 증가하고, 화면에 보여지는 값이 업데이트됩니다.

2.2 상태 값의 타입 추론

useState Hook을 사용할 때, 상태 값의 타입을 명시적으로 지정하지 않아도 자동으로 타입을 추론할 수 있습니다.

import React, { useState } from 'react';

function Example() {
  const [name, setName] = useState('John');
  const [age, setAge] = useState(25);
  const [isAdmin, setIsAdmin] = useState(false);

  return (
    

Name: {name}

Age: {age}

IsAdmin: {isAdmin ? 'Yes' : 'No'}

); } export default Example;

위의 예시에서는 useState Hook을 사용하여 name, age, isAdmin 세 개의 상태 값을 정의하고 초기값을 설정했습니다. 이렇게 하면 각각의 상태 값은 자동으로 해당 값의 타입을 가지게 됩니다.


3. useEffect Hook 사용 방법

useEffect Hook을 사용하면 함수형 컴포넌트에서 사이드 이펙트를 처리할 수 있습니다. 사이드 이펙트란 컴포넌트 외부에 영향을 주는 작업으로, 데이터 가져오기, 구독하기, 이벤트 처리 등을 포함할 수 있습니다.

3.1 기본 사용 방법

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

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Count: ${count}`;
  });

  return (
    

Count: {count}

); } export default Example;

이 예시에서는 useState Hook을 사용하여 count라는 상태 값을 정의하고, setCount 함수를 통해 상태 값을 변경합니다. useEffect Hook을 사용하여 컴포넌트가 렌더링될 때마다 document.title을 업데이트합니다. count 값이 변경될 때마다 title이 업데이트되어 화면 상단의 제목도 함께 변경됩니다.

3.2 의존성 배열 사용

useEffect Hook의 두 번째 인자로 의존성 배열(dependency array)을 전달할 수 있습니다. 이를 통해 특정 값이 변경될 때만 사이드 이펙트를 수행하도록 제한할 수 있습니다.

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

function Example() {
  const [count, setCount] = useState(0);
  const [message, setMessage] = useState('');

  useEffect(() => {
    setMessage(`Count is now ${count}`);
  }, [count]);

  return (
    

Count: {count}

{message}

); } export default Example;

위의 예시에서는 useEffect Hook의 의존성 배열에 count를 추가했습니다. 이렇게 하면 count 값이 변경될 때만 setMessage 함수가 호출되어 message가 변경됩니다.


4. useContext Hook 사용 방법

useContext Hook을 사용하면 함수형 컴포넌트에서 Context를 사용할 수 있습니다. Context는 컴포넌트 트리 안에서 전역적으로 데이터를 공유하기 위한 방법입니다.

4.1 Context 생성

먼저 Context를 생성하고 공유할 데이터를 제공하는 컴포넌트를 작성해야 합니다.

import React, { createContext } from 'react';

const ThemeContext = createContext('light');

export default ThemeContext;

위의 예시에서는 createContext를 사용하여 ThemeContext라는 Context를 생성합니다. createContext 함수의 인자로는 기본값을 전달할 수 있습니다. 이 기본값은 Context를 사용하는 컴포넌트에서 제공되지 않을 경우에 사용됩니다.

4.2 Context 사용

Context를 사용하려는 컴포넌트에서 useContext Hook을 사용하여 Context 값을 받아올 수 있습니다.

import React, { useContext } from 'react';
import ThemeContext from './ThemeContext';

function Example() {
  const theme = useContext(ThemeContext);

  return (
    

Current Theme: {theme}

); } export default Example;

위의 예시에서는 Example 컴포넌트에서 ThemeContext 값을 받아와 theme이라는 변수에 할당합니다. useContext Hook을 사용하면 ThemeContext.Provider로부터 제공된 값을 쉽게 가져올 수 있습니다.


5. useReducer Hook 사용 방법

useReducer Hook을 사용하면 함수형 컴포넌트에서 복잡한 상태 관리 로직을 더 효과적으로 처리할 수 있습니다. useReducer는 Redux와 유사한 패턴을 사용하여 상태를 업데이트하는 함수를 작성할 수 있도록 합니다.

5.1 초기 상태와 리듀서 함수 정의하기

먼저 초기 상태와 리듀서 함수를 정의해야 합니다. 리듀서 함수는 현재 상태와 액션을 받아 새로운 상태를 반환하는 역할을 합니다.

const initialState = 0;

function reducer(state, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

위의 예시에서는 초기 상태를 0으로 정의하고, 리듀서 함수를 작성했습니다. 리듀서 함수는 switch 문을 사용하여 액션의 타입에 따라 상태를 업데이트합니다.

5.2 useReducer Hook 사용하기

useReducer Hook을 사용하여 상태와 디스패치(dispatch) 함수를 받아올 수 있습니다.

import React, { useReducer } from 'react';

function Example() {
  const [count, dispatch] = useReducer(reducer, initialState);

  return (
    

Count: {count}

); } export default Example;

위의 예시에서는 useReducer Hook을 사용하여 count와 dispatch 함수를 받아왔습니다. dispatch 함수를 사용하여 액션을 디스패치하면 리듀서 함수가 호출되어 상태를 업데이트합니다. 버튼을 클릭하면 dispatch 함수를 호출하여 액션을 디스패치하도록 설정했습니다.


6. useCallback Hook 사용 방법

useCallback Hook은 메모이제이션된 콜백 함수를 생성할 수 있게 해주어 불필요한 렌더링을 방지하는데 도움을 줍니다. 이를 사용하여 성능을 최적화할 수 있습니다.

6.1 useCallback Hook 사용하기

useCallback Hook을 사용하여 콜백 함수를 메모이제이션할 수 있습니다.

import React, { useCallback } from 'react';

function Example() {
  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, []);

  return (
    

Example Component

); } export default Example;

위의 예시에서는 handleClick이라는 콜백 함수를 useCallback을 사용하여 메모이제이션하였습니다. useCallback의 첫 번째 인자는 콜백 함수 자체이고, 두 번째 인자는 의존성 배열입니다. 의존성 배열은 해당 콜백 함수가 의존하는 상태나 변수를 명시적으로 지정할 수 있습니다. 의존성 배열이 빈 배열인 경우 콜백 함수는 컴포넌트 마운트 시에만 생성됩니다.

6.2 의존성 배열의 사용

만약 의존성 배열이 존재한다면 해당 의존성이 변경될 때에만 메모이제이션된 콜백 함수가 새로 생성됩니다.

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

function Example() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log('Button clicked');
    setCount(count + 1);
  }, [count]);

  return (
    

Count: {count}

); } export default Example;

위의 예시에서는 count 상태를 의존성 배열에 추가하여, count가 변경될 때마다 메모이제이션된 handleClick 함수가 새로 생성되도록 설정했습니다.


7. useMemo Hook 사용 방법

useMemo Hook은 연산 결과를 메모이제이션하여 불필요한 계산을 방지하는데 사용됩니다. 이를 통해 성능을 최적화할 수 있습니다.

7.1 useMemo Hook 사용하기

useMemo Hook을 사용하여 값을 메모이제이션할 수 있습니다.

import React, { useMemo } from 'react';

function Example() {
  const expensiveCalculation = useMemo(() => {
    console.log('Expensive calculation performed');
    // 복잡한 계산 작업
    return 10 + 20;
  }, []);

  return (
    

Example Component

Result: {expensiveCalculation}

); } export default Example;

위의 예시에서는 expensiveCalculation이라는 변수를 useMemo을 사용하여 메모이제이션하였습니다. useMemo의 첫 번째 인자는 연산을 수행하는 함수이고, 두 번째 인자는 의존성 배열입니다. 의존성 배열이 빈 배열인 경우 연산은 컴포넌트 마운트 시에만 수행됩니다.

7.2 의존성 배열의 사용

만약 의존성 배열이 존재한다면 해당 의존성이 변경될 때마다 연산이 수행됩니다.

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

function Example() {
  const [count, setCount] = useState(0);

  const expensiveCalculation = useMemo(() => {
    console.log('Expensive calculation performed');
    // count에 따라서 계산 작업
    return count * 2;
  }, [count]);

  return (
    

Count: {count}

Result: {expensiveCalculation}

); } export default Example;

위의 예시에서는 count 상태를 의존성 배열에 추가하여, count가 변경될 때마다 연산이 수행되도록 설정했습니다. count가 변경될 때마다 “Expensive calculation performed”가 콘솔에 출력되고, 결과 값이 화면에 업데이트됩니다.


8. useRef Hook 사용 방법

useRef Hook은 값을 기억하고 업데이트하기 위해 사용됩니다. 이를 통해 DOM 요소에 접근하거나 이전 값과 현재 값을 비교하는 등의 작업을 수행할 수 있습니다.

8.1 useRef Hook 사용하기

useRef Hook을 사용하여 변수를 생성하고 값을 저장할 수 있습니다.

import React, { useRef } from 'react';

function Example() {
  const inputRef = useRef(null);

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

  return (
    

Example Component

); } export default Example;

위의 예시에서는 useRef를 사용하여 inputRef라는 변수를 생성하고, input 요소에 ref 속성으로 할당하였습니다. 이후 handleClick 함수를 통해 input 요소에 포커스를 주는 작업을 수행할 수 있습니다.

8.2 useRef를 사용한 값의 기억

useRef를 사용하여 이전 값과 현재 값을 비교할 수 있습니다.

import React, { useRef, useEffect } from 'react';

function Example() {
  const previousCountRef = useRef(0);
  const count = 3;

  useEffect(() => {
    previousCountRef.current = count;
  });

  return (
    

Previous Count: {previousCountRef.current}

Current Count: {count}

); } export default Example;

위의 예시에서는 useRef를 사용하여 previousCountRef라는 변수를 생성하고, 초기값을 0으로 설정했습니다. 이후 useEffect Hook을 사용하여 count 변수가 변경될 때마다 previousCountRef.current에 현재 count 값을 저장하도록 설정했습니다.


9. 커스텀 Hook 만들기

커스텀 Hook은 React 로직을 재사용하기 위해 사용되는 함수입니다. 이를 통해 컴포넌트 간에 로직을 공유하고, 코드의 재사용성과 가독성을 향상시킬 수 있습니다.

9.1 커스텀 Hook 생성하기

커스텀 Hook은 보통 “use”로 시작하는 함수로 작성됩니다. 다른 Hook을 사용할 수도 있으며, 상태와 이펙트를 관리하는 로직 등을 포함할 수 있습니다.

다음은 커스텀 Hook의 예시입니다:

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

function useFetch(url) {
  const [data, setData] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      const response = await fetch(url);
      const result = await response.json();
      setData(result);
    };

    fetchData();
  }, [url]);

  return data;
}

function Example() {
  const data = useFetch('https://api.example.com/data');

  return (
    

Example Component

{data &&

Data: {data}

}
); } export default Example;

위의 예시에서는 useFetch라는 커스텀 Hook을 생성하였습니다. 이 Hook은 주어진 URL로부터 데이터를 가져와서 상태로 관리하고, 데이터를 반환합니다. 이후 Example 컴포넌트에서 useFetch Hook을 사용하여 데이터를 가져오고 출력합니다.

9.2 커스텀 Hook 사용하기

커스텀 Hook은 일반적인 Hook과 마찬가지로 사용할 수 있으며, 여러 컴포넌트에서 재사용할 수 있습니다.

import React from 'react';
import useFetch from './useFetch';

function Example1() {
  const data = useFetch('https://api.example.com/data1');

  return (
    

Example 1 Component

{data &&

Data: {data}

}
); } function Example2() { const data = useFetch('https://api.example.com/data2'); return (

Example 2 Component

{data &&

Data: {data}

}
); } export default function App() { return (
); }

위의 예시에서는 Example1 컴포넌트와 Example2 컴포넌트에서 동일한 useFetch Hook을 사용하여 다른 URL에서 데이터를 가져오고 출력합니다. 이렇게 커스텀 Hook을 사용함으로써 데이터 가져오기 로직을 재사용할 수 있습니다.


10. Hooks 사용 시 주의사항

Hooks를 사용할 때 몇 가지 주의사항을 알아야 합니다. 이러한 주의사항을 명확히 이해하고 지키는 것은 안정적이고 예측 가능한 컴포넌트를 작성하는 데 도움이 됩니다.

10.1 Hooks를 컴포넌트의 최상위 레벨에서만 호출하기

Hooks는 컴포넌트의 최상위 레벨에서만 호출되어야 합니다. 루프, 조건문, 중첩된 함수 내에서 Hooks를 호출해서는 안 됩니다. 이러한 제약은 Hooks의 실행 순서와 의도치 않은 동작을 피하기 위해서입니다.

잘못된 예시:

import React, { useState } from 'react';

function Example() {
  if (condition) {
    const [count, setCount] = useState(0); // 잘못된 위치
  }

  return (
    

Example Component

{count}

); } export default Example;

10.2 Hooks를 실행하는 조건문 사용하기

Hooks를 실행하는 조건문을 사용할 때는 주의해야 합니다. 조건문 내부에서 Hooks를 실행해야 한다면, 조건문 자체도 컴포넌트의 최상위 레벨에서 실행되는 것을 보장해야 합니다.

올바른 예시:

import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);
  
  if (condition) {
    setCount(5);
  }

  return (
    

Example Component

{count}

); } export default Example;

10.3 Custom Hook의 이름 작성하기

Custom Hook의 이름은 항상 `use`로 시작해야 합니다. 이렇게 작성함으로써, Custom Hook 안에서 다른 Hook을 호출하는 것을 잊지 않도록 도와줍니다.

올바른 예시:

import React, { useState } from 'react';

function useCustomHook() {
  const [value, setValue] = useState('');

  return [value, setValue];
}

10.4 useEffect Hook의 의존성 배열 지정하기

useEffect Hook을 사용할 때, 의존성 배열을 지정해주는 것이 중요합니다. 의존성 배열에 포함되지 않은 값들은 useEffect Hook 안에서 접근할 수 없게 됩니다.

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

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log('Count changed!');
  }, [count]);

  return (
    

Example Component

{count}

); } export default Example;

위의 예시에서는 count 상태가 변경될 때만 useEffect Hook이 실행되도록 의존성 배열에 count를 포함시켰습니다.

10.5 ESLint 플러그인 사용하기

Hooks를 사용할 때, 로직의 오류를 방지하기 위해 ESLint 플러그인을 사용하는 것이 좋습니다. 예를 들어, ESLint의 `eslint-plugin-react-hooks` 플러그인은 Hooks 규칙에 대한 경고를 제공합니다.


Leave a Comment