검색 기능을 구현 중 onChange를 이용하여 구현할 경우, 사용자가 입력하는 모든 값 하나하나가 입력이 된다.
만약 서울을 검색하는 걸 콘솔창에 찍어보면 ㅅ, 서, 서ㅇ,서우,서울이 출력된다.
onChenge로 바뀌는 값으로 api 호출을 한다면 마지막 서울을 뺀 나머지는 필요없는 호출이 되는 셈이다.
필요없는 호출로 인한 낭비를 줄이기 위해 debounce를 사용한다.
debounce는 딜레이를 주고 그 딜레이가 끝날 때의 코드만 실행한다.
난 lodash의 debounce라이브러리를 사용했고 아래가 debounce를 사용한 onChange 코드다.
import { debounce } from 'lodash';
const [searchValue, setSearchValue] = useState('');
const debounceOnChange = debounce((e) => {
setSearchValue(e);
}, 1000);
const onChangeSearchValue = (event: ChangeEvent<HTMLInputElement>) => {
debounceOnChange(event.target.value);
};
위 코드는 제대로 동작하지 않는다.
왜냐하면, 리렌더링 되는 컴포넌트 내에 debounce를 정의한 함수가 있고,
해당 컴포넌트가 state에 따라 리렌더링이 된다면 debounce 함수도 재생성되면서 debounce가 초기화되기 때문이다.
그래서 useMemo를 사용해서 아래와 같은 코드가 되었다.
import { debounce } from 'lodash';
const [searchValue, setSearchValue] = useState('');
const debounceOnChange = useMemo(
() => debounce((e) => setSearchValue(e), 1000),
[]
);
const onChangeSearchValue = (event: ChangeEvent<HTMLInputElement>) => {
debounceOnChange(event.target.value);
};
useMemo의 memo는 memoization을 뜻한다.
memoization이란 기존에 수행한 연산의 결과값을 어딘가에 저장해두고 동일한 입력이 들어오면 재활용하는 프로그래밍 기법을 말한다.
const Component = () => {
const value = getPostDate();
return <div>{value}</div>
}
const getPostDate = () => {
return 20230101;
}
만약 위 코드가 있다고 가정해보자
함수형 컴포넌트는 렌더링 -> Component의 함수 호출 -> 모든 내부 변수 초기화의 순서를 거친다.
Component가 렌더링 될 때마다 안에 있는 변수(value)가 초기화 되는데,
만약 그 변수가 엄청 무거운 일을 반복적으로 하는 함수라면? 엄청 비효율적일 것이다.
그에 반해 useMemo는 렌더링 -> Component의 함수 호출 -> memoization된 함수를 재사용하는 순서를 거친다.
useMemo로 memoization을 해주면 getPostDate함수를 반복적으로 실행할 필요가 없다.
처음 계산된 결과값을 메모리에 저장한 후, 반복적으로 렌더링이 되면 getPostDate를 다시 호출하지 않고 저장된 결과값을 사용하기 때문이다.