본문 바로가기
부트캠프

멋쟁이사자처럼 프론트엔드 부트캠프 14기 - Day 82 (useMemo 훅, useCallback 훅, 사용자 정의 훅 함수)

by 나른한_꼬리_ 2025. 9. 2.
반응형

멋쟁이사자처럼 프론트엔드 부트캠프 14기 - Day 82 (useMemo 훅, useCallback 훅, 사용자 정의 훅 함수)

 

목차

 

 

프론트엔드 개발에서 성능을 최적화하고 코드를 효율적으로 관리하는 것은 매우 중요하다. 리액트는 이러한 문제를 해결하기 위해 useMemouseCallback과 같은 훅과 사용자 정의 훅(커스텀 훅 custom hooks)이라는 강력한 기능을 제공한다.

 

 

useMemo 훅

useMemo는 메모이제이션(Memoization)을 활용하여 불필요한 반복 계산을 줄여주는 훅이다. 메모이제이션은 한 번 계산한 결과를 저장해 두었다가 동일한 입력이 들어오면 재계산 없이 저장된 값을 반환하는 기법이다.

 

컴포넌트가 리렌더링될 때마다 반복되는 대규모 데이터 필터링, 복잡한 수학 연산 등 비용이 많이 드는 계산을 최적화하기 위해 useMemo를 사용한다. useMemo는 의존성 배열에 있는 값이 변경될 때만 내부 계산을 다시 실행하고, 그렇지 않으면 이전 결과를 재사용한다.

import { useState, useMemo } from 'react'

const LIST = Array.from({ length: 1e6 }).map((_, i) => i)

export default function App() {
  const [query, setQuery] = useState('')

  // 검색어(query)가 바뀔 때에만 필터링 실행
  const filteredList = useMemo(() => {
    console.time('filtering')
    const result = LIST.filter((n) => n.toString().includes(query))
    console.timeEnd('filtering')
    return result
  }, [query])

  // ...
}

 

 

useCallback 훅

컴포넌트가 리렌더링될 때마다 함수가 새로 생성되면, 이 함수를 의존성 배열에 포함하는 useEffect나 다른 훅이 불필요하게 다시 실행될 수 있다. useCallback은 이런 문제를 해결하기 위한 훅이다. useCallback은 함수 자체를 메모이제이션하여 컴포넌트가 리렌더링되더라도 함수가 새로 생성되지 않도록 한다.

특정 값의 재계산을 방지하는 useMemo와 달리, useCallback은 특정 함수의 재생성을 방지한다. 실제로는 useCallback이 useMemo를 기반으로 만들어졌기 때문에, 함수 메모이제이션에 더 직관적인 문법을 제공하는 도우미 훅이라고 볼 수 있다.

 

따라서, 고비용 계산의 결과를 저장하고 싶을 때는 useMemo를 사용하고, 함수 자체의 재생성을 막고 싶을 때는 useCallback을 사용하면 된다. 단, 성능 문제가 명확하게 드러날 때만 선택적으로 사용하는 것이 좋다.

 

 

사용자 정의 훅 함수

사용자 정의 훅 함수는 리액트의 기본 훅(useStateuseEffect 등)을 조합하여 자주 사용되는 로직을 함수로 분리하고 재사용할 수 있게 해주는 기능이다. 토글 상태 관리, 입력값 관리, 데이터 페칭 등 여러 컴포넌트에서 반복적으로 사용되는 로직의 중복을 제거하고, 코드를 더 간결하고 읽기 쉽게 만들어서 유지보수성을 높인다.

사용자 정의 훅 함수 이름은 반드시 use로 시작해야 한다. 함수 내부에 필요한 훅을 사용하고, 외부에서 사용할 값이나 함수를 반환한다. 예를 들어 불리언 값을 토글하는 useToggleState나 입력값을 관리하는 useInputValue와 같은 사용자 정의 훅 함수를 만들어 여러 컴포넌트에서 재사용할 수 있다.

// useToggleState.ts
import { useState, useCallback } from 'react'

/**
 * 불리언 상태를 토글하는 커스텀 훅
 *
 * @param {boolean} [initialValue=false] - 초기 상태 값 (기본값: false)
 * @returns {[boolean, () => void]} 
 *   첫 번째 값: 현재 상태 (boolean)
 *   두 번째 값: 상태를 토글하는 함수
 *
 * @example
 * const [isOpen, toggleOpen] = useToggleState()
 * <button type="button" onClick={toggleOpen}>{isOpen ? '닫기' : '열기'}</button>
 */
export default function useToggleState(initialValue = false) {
	const [value, setValue] = useState(initialValue)
	const toggle = useCallback(() => setValue(v => !v), [])
	return [value, toggle]
}

 

사용자 정의 훅을 활용하면 복잡한 로직을 컴포넌트로부터 분리해 코드를 더욱 추상화하고, 재사용성화 가독성을 크게 향상시킬 수 있다.

 

오늘 하루를 돌아보며

오늘은 커스텀 훅을 만들어봤다. useArrayuseQuery 커스텀 훅이다. useArray는 배열(혹은 배열을 반환하는 함수)의 상태 관리 전용 훅이다. 배열을 받아서 배열 전체를 새로운 값으로 설정하거나, 배열에 새 요소를 추가하거나, 특정 인덱스의 요소를 새 값으로 교체하거나 삭제하거나, 필터링하거나, 배열을 비우거나, 초기값으로 리셋하는 기능을 추가했다.

 

useQuery데이터 페칭(Data Fetching) 로직을 재사용할 수 있는 커스텀 훅이다. 요청 상태, 요청 중 에러, fetch 요청으로 받아온 데이터, 로딩 상태 여부, 오류 포함 여부, 재요청 함수를 객체 형태로 반환한다. 이렇게 하면 데이터 페칭을 할 때 여러 컴포넌트에서 같은 로직을 여러 번 사용하지 않아도 돼서 간결하게 코드를 짤 수 있게 된다.

 

유용한 커스텀 훅을 잘 만들어 놓으면 프로젝트를 하거나 실무에 나가서도 다른 사람들과 공유할 수도 있고, 여러 컴포넌트에 반복적으로 로직을 사용하지 않아도 돼서 좋을 것 같다. 자주 사용하게 되는 로직을 커스텀 훅으로 작성할 수 있도록 반복되는 것에 주의를 기울여야겠다. 강사님도 지난 과제에서 함수를 사용하지 않아서 코드가 길어진 사람들이 있다고 하셨다. 반복되는 것이 있다면 함수로 빼거나 커스텀 훅을 만들면 유용할 것 같다.

 

반응형