useCallback은 리액트 컴포넌트에서 함수를 메모제이션(Memoization) 하는 데 사용되는 훅이다.
쉽게 말해, 불필요하게 함수를 다시 생성하지 않고, 이전에 생성한 함수를 재사용 하는 기능을 제공한다.
컴포넌트가 렌더링될 때마다 함수가 새로 생성되는데, 어떤 상황에서는 매번 새로 생성하지 않고 이전에 생성한 함수를 그대로 재사용하는 것이 성능에 더 유리할 수 있다.
예를 들어:
자식 컴포넌트에 함수를 props로 전달할 때: 부모 컴포넌트가 렌더링될 때마다 새로운 함수가 자식 컴포넌트에 전달 되면, 자식 컴포넌트도 불필요하게 다시 렌더링이 될 수 있다.
비용이 많이 드는 연산을 포함한 함수를 반복적으로 생성하지 않기 위해.
import React, { useCallback, useState } from "react";
function ParentComponent() {
const [count, setCount] = useState(0);
// `useCallback` 없이 작성
const handleClick = () => {
console.log("Button clicked");
};
return (
<div>
<ChildComponent onClick={handleClick} />
<button onClick={() => setCount(count + 1)}>Increment Parent Count</button>
</div>
);
}
function ChildComponent({ onClick }) {
console.log("Child rendered");
return <button onClick={onClick}>Click me</button>;
}
사실 이 코드도 나한테는 아직 어렵다.... 하나하나 풀어보자...
const [count, setCount] = useState(0);
useState: 상태 관리를 위해 사용하는 React 훅이다.
count: 현재 상태 값을 나타내는 변수이다. 초기값은 0이다.
setCount: 상태를 업데이트하는 함수이다.
호출하면 count의 값이 변경되고, 컴포넌트가 다시 렌더링된다.
const handleClick = () => {
console.log("Button clicked");
}
function ChildComponent({ onClick }) {
console.log("Child rendered");
return <button onClick={onClick}>Click me</button>;
}
<button onClick={() => setCount(count + 1)}>Increment Parent Count</button>
ParentComponent가 렌더링될 때마다 새로운 handleClick 함수가 생성된다.
React는 props가 변경되면 자식 컴포넌트를 다시 렌더링하므로, ChildComponent가 불필요하게 다시 렌더링이 된다.
import React, { useCallback, useState } from "react";
function ParentComponent() {
const [count, setCount] = useState(0);
// `useCallback` 적용
const handleClick = useCallback(() => {
console.log("Button clicked");
}, []); // 의존성 배열이 비어 있으므로 handleClick은 항상 동일한 함수 참조를 유지
return (
<div>
<ChildComponent onClick={handleClick} />
<button onClick={() => setCount(count + 1)}>Increment Parent Count</button>
</div>
);
}
function ChildComponent({ onClick }) {
console.log("Child rendered");
return <button onClick={onClick}>Click me</button>;
}
위 코드에서 useCallback을 사용하면, handleClick 함수가 매번 새로 생성되지 않고, 항상 동일한 함수를 사용하게 된다. 따라서 ChildComponent는 불필요하게 다시 렌더링이 되지 않는다.
const memoizedCallback = useCallback(
() => {
// 실행할 함수
},
[dependency1, dependency2] // 의존성 배열
);
useCallback은 최적화 도구이므로, 모든 경우에 사용하지 않아도 된다. 성능상의 이점이 필요한 경우에만 적용한다.