useCallback으로 래핑)import { useCallback, useState } from "react";
import debounce from "lodash-es/debounce";
export default function SearchBoxBad() {
const [value, setValue] = useState("");
// ❌ 이렇게 쓰면 렌더마다 debounce(...)가 실행 → 항상 새 함수 생성
const handleSearch = useCallback(
debounce((v: string) => {
console.log("검색 실행:", v);
}, 1000),
[]
);
return (
<inputvalue={value}
onChange={(e) => {
setValue(e.target.value);
handleSearch(e.target.value);
}}
/>
);
}
debounce(...)가 새로 만들어짐useMemo로 debounce 함수 인스턴스 고정)import { useMemo, useState } from "react";
import debounce from "lodash-es/debounce";
export default function SearchBoxGood() {
const [value, setValue] = useState("");
// ✅ debounce 결과 "함수 인스턴스"를 값처럼 메모이즈
const handleSearch = useMemo(
() =>
debounce((v: string) => {
console.log("검색 실행:", v);
}, 1000),
[]
);
return (
<inputvalue={value}
onChange={(e) => {
setValue(e.target.value);
handleSearch(e.target.value);
}}
/>
);
}
debounce(...)를 새로 안 만들고, 같은 디바운스 함수를 재사용useCallback은 “이 함수를 다시 만들지 마” 용 → 함수 본문을 직접 정의할 때 유용useMemo는 “이 값(=debounce가 만든 함수 객체)을 그대로 재사용해” 용 → 라이브러리에서 만들어주는 함수/객체를 캐싱할 때 유용즉,
useCallback(fn, deps) = useMemo(() => fn, deps)
하지만 debounce(fn, wait)는 fn을 감싼 “새 함수 객체”를 리턴하므로 → useMemo로 그 값을 캐싱하는 게 맞습니다.
“디바운스처럼 내부 상태(타이머) 를 가진 함수는 useMemo로 고정”