구름톤 유니브☁️ 4기 FE 스터디

서론

이번 포스팅에서는 리액트 Hooks 중 useMemo(), useCallback(), useRef() Hook에 대해 알아보고자 합니다.


본론

1. useMemo()

useMemo는 memoized value, 즉 “기억된 값”을 리턴해주는 Hook이다.

📖 Memoization이란?

최적화를 위해 사용하는 개념으로

비용이 높은 함수의 호출 결과를 저장해두었다가 같은 입력이 들어오면 다시 계산하지 않고 이전에 저장했던 결과를 반환한다.

따라서 불필요한 중복 연산을 줄여 리소스를 적게 사용하는 최적화 기법이다.

const memoizedValue = useMemo(
	() => {
    	// 연산량이 높은 작업을 수행하여 결과를 반환
        return computeExpensiveValue(의존성 변수, 의존성 변수2);
    },
    [의존성 변수1, 의존성 변수2]
);

 

✅ useMemo()의 동작 방식

  • 첫 번째 파라미터: 계산할 함수 (memoized value를 생성하는 함수)
  • 두 번째 파라미터: 의존성 배열

📌 의존성 배열의 값이 바뀔 때만 내부 함수가 실행되고, 그 외에는 이전 계산 값을 그대로 반환한다. => 빠른 렌더링 속도

📌 이 때, useMemo()로 전달되는 함수는 렌더링이 일어나는 동안에만 실행된다.
      즉, sideEffect와 같은 렌더링이 일어나는 동안에 일어나면 안될 작업을 useMemo()에서 수행해선 안된다.

 

의존성 배열이 없다면?
const memoizedValue = useMemo(
	() => computeExpensiveValue(a, b)
);

위 코드와 같이 useMemo()를 사용할 때 의존성 배열이 없을 경우 매 렌더링마다 함수가 실행된다.

이는 useMemo()를 사용하는 의미가 없는 행위이므로, 의존성 배열을 명확히 넣어주도록 하자

의존성 배열이 빈 배열이라면?
const memoizedValue = useMemo(
	() => {
    	return computeExpensiveValue(a, b);
    },
    []
);

위 코드와 같이 의존성 배열이 빈 배열일 경우에는 컴포넌트가 처음 마운트될 때 함수가 실행된다.

따라서 마운트 시점에만 필요한 연산(초기화 등)에 주로 사용된다.


2. useCallback()

useCallback은 useMemo와 거의 똑같이 생겼지만, 값이 아닌 “함수”를 기억하고 반환한다는 점에서 다르다.

useCallback()은 주로 props로 자식 컴포넌트에 함수를 넘겨줄 때, 불필요한 리렌더링을 방지하고자 할 때 사용한다.

const memoizedCallback = useCallback(
	() => {
    	doSomething(의존성 변수1, 의존성 변수2);
    },
    [의존성 변수1, 의존성 변수2]
);

 

✅ useCallback()의 동작 방식

  • 첫 번째 파라미터: 계산할 함수 (memoized value를 생성하는 함수) 
  • 두 번째 파라미터: 의존성 배열 

계산할 함수는 콜백이라고 부르고, 의존성 배열의 변수가 변경될 경우 memoization된 콜백함수를 반환한다.

import { useState, useCallback } from 'react';

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

  // 컴포넌트가 마운트 될 때만 함수가 정의됨
  const handleClick = useCallback((event) => {
    // 클릭 이벤트 처리
  }, []);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>
        {count}
      </button>
      <ChildComponent handleClick={handleClick} />
    </div>
  );
}

export default ParentComponent;

위와 같이 hadleClick 함수를 useCallback을 사용하여 정의하게 되었고 의존성 배열을 빈 배열로 두었으므로,

컴포넌트가 마운트 될 때만 함수가 정의된다. 따라서 함수의 불필요한 리렌더링(정의)를 줄일 수 있게 된다.


3. useRef()

useRef()는 컴포넌트 내에서 어떤 값을 기억하거나 특정 DOM 요소를 직접 참조하고 싶을 때 사용한다.

참조(Reference)란 특정 컴포넌트에 접근할 수 있는 객체를 의미한다.

const inputRef = useRef();

<input ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Focus</button>

 

 

📖 useRef()

  • useRef()는 파라미터로 초기값을 넣으면 초기화된 Reference 객체를 반환한다.
  • Reference 객체는 컴포넌트 생명주기 전체에 걸쳐 유지된다.
  • useRef()는 변경가능한 current라는 속성을 가진 하나의 상자라고 생각하면 된다.
function TextInputWithFocusButton(props) {
  const inputElem = useRef(null);

  const onButtonClick = () => {
    // current는 마운트된 input element를 가리킴
    inputElem.current.focus();
  };

  return (
    <>
      <input ref={inputElem} type="text" />
      <button onClick={onButtonClick}>
        Focus the input
      </button>
    </>
  );
}

 

useRef()는 내부의 데이터가 변경되었을 때 별도로 알리지 않는다는 점을 기억하자

이는 속성 변경이 리렌더링으로 이어지지 않는다는 것을 의미한다.

 

📖 Callback Ref
function MeasureExample(props) {
  const [height, setHeight] = useState(0);

  const measuredRef = useCallback((node) => {
    if (node !== null) {
      setHeight(node.getBoundingClientRect().height);
    }
  }, []);

  return (
    <>
      <h1 ref={measuredRef}>안녕, 리액트</h1>
      <h2>위 헤더의 높이는 {Math.round(height)} 입니다.</h2>
    </>
  );
}

callback ref방식을 사용하면 자식 컴포넌트가 변경되었을 때 알림을 받을 수 있고 이를 통해 다른 정보들을 업데이트 할 수 있다.

<h1>태그가 마운트 언마운트 될때만 업데이트가 일어나는 것

 

 


마무리

이번 글에서는 useMemo(), useCallback(), useRef() 훅을 다뤄보았는데 전체적인 내용을 요약하자면

Hook 역할 반환 값 주 용도
useMemo() 연산 결과를 기억 무거운 계산 최적화
useCallback() 함수 자체를 기억 함수 자식 컴포넌트 리렌더링 방지 등
useRef() DOM 참조 / 값 저장 ref 객체 DOM 제어, 렌더링 영향 없는 변수 저장

 

오늘도 읽어주셔서 감사합니다 🫡

'TIL > React' 카테고리의 다른 글

[React] Composition vs Inheritance  (0) 2025.05.13
[React] Handling Events & Conditional Rendering & List and Keys  (1) 2025.05.06
[React] JSX & Rendering Elements  (0) 2025.04.08
[React] React.js란?  (0) 2025.04.08

+ Recent posts