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]);