All'alba vincerò

At dawn, I will win!

React

[React] useMemo()와 useCallback()의 차이: 값과 함수의 메모이제이션

나디아 Nadia 2024. 12. 31. 17:52

useMemo()

: 계산된 값 메모이제이션

  • 값을 다룰 때 사용
  • 비싼 계산을 다시 하지 않도록 최적화
  • 리렌더링 중에도 이전에 계산된 값을 재사용
import React, { useState, useMemo } from 'react';

function ExpensiveCalculationExample() {
  const [count, setCount] = useState(0);
  const [list, setList] = useState([1, 2, 3, 4, 5]);

  // 값 메모이제이션
  const expensiveResult = useMemo(() => {
    console.log("Expensive calculation...");
    
    return list.reduce((sum, num) => sum + num ** 2, 0);
  }, [list]);

  return (
    <div>
      <p>Expensive Result: {expensiveResult}</p>
      <button onClick={() => setCount(count + 1)}>Increment Count ({count})</button>
    </div>
  );
}

// 버튼 클릭으로 상태(count)가 변경되더라도 useMemo 덕분에 sum을 다시 계산하지 않음

 

 

 

useCallback()

: 함수 메모이제이션

  • 함수를 다룰 때 사용
  • 특정 함수를 계속 새로 생성하지 않도록 최적화
  • 주로 자식 컴포넌트에 전달하는 함수에서 사용
import React, { useState, useCallback } from 'react';

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

  // 함수 메모이제이션(자식 컴포넌트로 전달할 함수)
  const handleClick = useCallback(() => {
    console.log("Button clicked!");
  }, []);

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

function ChildComponent({ onClick }) {
  console.log("ChildComponent rendered");
  return <button onClick={onClick}>Click me</button>;
}

// Parent 컴포넌트가 리렌더링되어도 useCallback 덕분에 handleClick은 새로 생성되지 않음
// 이로 인해 자식 컴포넌트인 Child가 불필요하게 리렌더링되는 것을 방지함

 

 


1. 공통점

  • 메모이제이션을 통해 불필요한 작업을 방지하여 성능을 최적화

 

 

 

2. 차이점

  useMemo  useCallback
역할 계산된 값을 메모이제이션 함수를 메모이제이션
반환값 계산된 값의 결과 메모이제이션된 함수
사용 사례 복잡한 계산, 필터링, 정렬 등 자식 컴포넌트에 함수를 props로 전달할 때

 

 

 

3. 사용하는 상황

계산된 값(useMemo): 값(결과)을 재사용

  • 복잡하거나 자주 반복되는 계산을 최적화
  • 계산 결과를 그대로 사용하거나 JSX에서 직접 활용할 때

 

함수(useCallback): 함수 자체를 재사용

  • 부모에서 자식 컴포넌트로 전달하는 함수가 리렌더링마다 새로 생성되지 않도록 방지
  • 부모에서 자식 컴포넌트로 props로 함수를 전달할 때

 

 

 

4. 예제: 메모이제이션 사용

1. useMemo를 활용한 복잡한 계산

  • list가 변경되지 않는 한, 계산(reduce)을 다시 실행하지 않는다.
  • 버튼 클릭(count 변경)만으로 계산이 다시 실행되지 않게 최적화한다.
import React, { useState, useMemo } from 'react';

function ExpensiveCalculationExample() {
  const [count, setCount] = useState(0);
  const [list, setList] = useState([1, 2, 3, 4, 5]);

  // 복잡한 계산
  const expensiveResult = useMemo(() => {
    console.log("Expensive calculation...");
    return list.reduce((sum, num) => sum + num ** 2, 0);
  }, [list]);

  return (
    <div>
      <p>Expensive Result: {expensiveResult}</p>
      <button onClick={() => setCount(count + 1)}>Increment Count ({count})</button>
    </div>
  );
}

 

 

 

2. useCallback을 활용한 함수 메모이제이션

  • handleClick 함수가 메모이제이션되어 부모가 리렌더링되더라도 자식 컴포넌트(ChildComponent)는 불필요한 리렌더링을 방지한다.
import React, { useState, useCallback } from 'react';

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

  // 자식 컴포넌트로 전달할 함수
  const handleClick = useCallback(() => {
    console.log("Button clicked!");
  }, []);

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

function ChildComponent({ onClick }) {
  console.log("ChildComponent rendered");
  return <button onClick={onClick}>Click me</button>;
}

 

 

 

5. 값과 함수의 차이

  계산된 값(Value) 함수(Function)
역할 계산 작업의 결과 (숫자, 문자열, 객체 등) 특정 동작(로직)을 실행하기 위한 코드 블록
예시 1 + 1 = 2 (결과) () => console.log("Hello") (동작)
목적 결과(데이터)를 활용 동작(작업)을 실행
메모이제이션 대상 계산된 값 자체를 저장 함수 자체를 저장하여 새로 생성되지 않도록 방지
React에서 사용 useMemo useCallback

 

 

 

 

6. 예제 비교: 같은 상황, 다른 메모이제이션

계산된 값(useMemo)

  • expensiveCalculation(input)의 결과 값이 메모이제이션 된다.
    (input이 바뀔 때만 계산 다시 실행)
// `expensiveCalculation`의 결과 값을 저장
const memoizedValue = useMemo(() => {
  return expensiveCalculation(input);
}, [input]);

 

 

함수(useCallback)

  • 함수 자체가 메모이제이션 된다.
    (dependency가 바뀔 때만 새로운 함수 생성)
// 함수 자체를 저장하여 같은 로직의 함수가 매번 생성되지 않음
const memoizedFunction = useCallback(() => {
  console.log("Performing action");
}, [dependency]);