React 훅
메모이제이션(반환 값을 캐싱하는 것, 리렌더링 사이의 계산 결과를 캐싱하는 것, 이전에 계산해둔 값을 메모리에 저장하여 중복 작업을 제거하는 것)으로 성능 최적화하는 데에 사용
사용 방법: useMemo(calculation function, dependencies)
calculation function은 인자가 없고, 원하는 값을 계산하여 반환하는 계산 함수이다. dependencies는 컴포넌트 내에서 계산에 사용되는 모든 값을 포함하는 의존성 목록이다.
첫 렌더링에서 useMemo로 얻는 값은 calculation functino을 호출한 결과값이다.
그 이후부터는 의존성 변경 여부에 따라 달라진다. 의존성이 변경되지 않았다면, 이전에 계산했던 값을 반환하고(계산 결과를 캐시하고), 변경되었다면 계산을 다시 하고 새로운 값을 반환한다.
주의사항 1 : React 훅이기 때문에 컴포넌트 최상위 레벨, 또는 커스텀 훅에서만 호출 가능. (반복문 내X, 조건문 내X -> 필요 시 새로운 컴포넌트를 생성하고 해당 컴포넌트로 state 이동)
주의사항 2 : 메모이제이션은 메모리를 추가적으로 더 사용하는 것이기 때문에 실제 연산 비용보다 비용이 더 클 수가 있다. 판단 기준으로는 계산 비용(연산 복잡도, 발생 빈도), 리렌더링 빈도, 의존성의 안정성 등이 있다.
const menuItems = useMemo(() => [
{ label: "전체", value: "전체" },
{ label: "정/가품", value: "정/가품" },
{ label: "Q & A", value: "Q & A" },
{ label: "자유", value: "자유" },
], []);
사실 복잡한 연산이 없기 때문에 useMemo를 사용할 필요가 없다. 하지만... 사용해 보고 싶었다.
React 훅
함수
를 메모이제이션하여 컴포넌트가 리렌더링할 때마다 동일한 함수 인스턴스를 재사용할 수 있게 한다. 종속성 배열 값이 변경되지 않는 한 이 함수는 새로 생성되지 않는다.
하위 컴포넌트에 콜백함수를 props로 전달할 때, 불필요한 리렌더링을 방지하는 데에 유용하다.
사용 방법 : const cachedFn = useCallback(fn, dependencies)
fn은 인자와 반환값 모두 가질 수 있다. React는 첫 렌더링에서 이 함수를 반환한다(호출 아님) 이후 렌더링에서 dependencies값이 동일하다면 같은 함수를 다시 반환하고, 변경되었다면 이번 렌더링에서 전달한 함수를 반환하고, 나중에 재사용할 수 있도록 저장한다. 함수를 호출하는 것이 아니다. React는 함수를 호출하지 않는다. dependencies는 fn 내에서 참조되는 props, state, 변수, 함수 등 모든 반응형 값의 목록이다.
주의사항 : 컴포넌트의 최상단에서 호출 가능
React는 특별한 이유가 없는 한 캐시된 함수를 삭제하지 않는다.
const getCommunity = useCallback(async () => {
// 커뮤니티 목록 get 코드
}, [myToken, selectedMenu, page]);
useEffect(() => {
getCommunity();
}, [getCommunity]);
이전 코드에서는 getCommunity 함수를 하나 만들고, useEffect에 getCommunity에 넣어놨었다. useEffect만 사용하면 내부에서 처리하는 일이 많아지고 코드가 복잡해진다. 의존성 배열도 길어져서 가독성이 떨어지는 문제가 있다.
useCallback을 사용하면 useEffect에서는 원하는 side Effect만 실행해 주고, 실제 처리해야 할 일은 useCallback에서 선언하여 코드를 분리할 수 있다.
근데 useCallback은 보통 자식 컴포넌트에게 props로 함수를 전달할 때 자식 컴포넌트의 불필요한 랜더링을 방지하기 위해 사용한다고 한다. 이 부분 말고 다른 부분에 사용하는 것이 더 적합한 것 같다
📎 참고자료
https://5kdk.tistory.com/39
리액트 공식문서