함수형 컴포넌트는 렌더링이 일어날 때마다 컴포넌트 전체가 다시 실행된다. 이 특징 때문에 괜한 자원 낭비가 일어날 수 있다. 처리가 오래 걸리는 함수의 리턴값을 매번 다시 받아 온다던지, 변수나 함수를 계속 생성한다던지... 이것을 방지하기 위해 useMemo(), useRef(), useCallback()이 있다.
useMemo로 컴포넌트도 기억할 수 있다. 쓸데없는 렌더링이 일어나지 않도록 최적화 하는 방법 중 하나이기도 하다.
const numbers = useMemo(() => {
return getNumbers();
},[바뀔여지가있는값])
useRef: 일반 값을 기억할 때 사용한다. 여기를 참고. 처음에 그냥 let 변수 선언해서 써도 동작은 잘 되던데 왜 useRef가 굳이 있지 싶었는데, 렌더링 될 때마다 함수형 컴포넌트는 그전체가 다시 실행되는 특징 때문에 useRef가 있는 것 같다. 그냥 let 변수를 사용하면 이 변수도 매번 다시 생성될테니까.
useCallback: 함수 자체를 기억한다. 그래서 렌더링이 일어날 때마다 함수형 컴포넌트 전체가 다시 실행되어도, useCallback으로 감싸놓은 함수는 다시 생성되지 않는다.
useCallback 안에서 state 값을 사용할 때는 []안에 그 state 값을 같이 넣어야 잘 사용할 수 있다. useEffect처럼 []안의 값이 바뀌면 useCallback도 다시 실행된다.
그리고 컴포넌트 안에 넣는 이벤트 함수들은 (onClick={on어쩌구} 이런 것들) 모두 useCallback으로 감싸자!!!
const onClickBtn = useCallback(() => {
// 함수형 컴포넌트 전체가 다시 실행되어도
// 이 onClickBtn()은 다시 생성되지 않음
const test = numbers;
}, [numbers]);
자식 컴포넌트에다가 함수를 props로 전달할 때, 그 전달하는 함수는 useCallback()을 꼭 쓰자. useCallback을 사용하지 않으면 부모 컴포넌트 전체가 매번 실행될 것이고 그러면 그 함수를 props로 받는 자식 컴포넌트도 매번 새로 실행되게 된다.