리액트에서 리렌더링이 자주 일어나는 것은 좋은 일이 아니다. 이러한 불필요한 리렌더링을 막기 위해서 우리는 최적화를 해야한다. 리액트에서 최적화하는 방법은 대표적으로
부모 컴포넌트가 리렌더링 되면 자식 컴포넌트도 모두 리렌더링이 된다. 자식 컴포넌트는 바뀐게 없어도 부모컴포넌트가 리렌더링되면 자식도 리렌더링이 되기 때문에 이것을 방지하는 것이 React.memo이다.
export default React.memo(Box1);
컴포넌트 export에 React.memo로 감싸기만 하면 된다.
React.memo는 컴포넌트를 메모이제이션 했다면, useCallback은 인자로 들어오는 함수 자체를 메모이제이션 한다.
// useCallback 사용 전
const initCount = () => {
setCount(0);
};
// useCallback 사용 후
const initCount = useCallback(() => {
setCount(0);
}, []);
useCallback의 의존성 배열에는 변경될 때마다 새롭게 함수를 할당하는 state같은 것들을 넣는다.
useMemo는 맨 처음 해당 값을 반환할 때 그 값을 메모리에 저장한다. 이렇게 하면 필요할 때마다 다시 함수를 호출해서 계산하는게 아니라 이미 저장한 값을 단순히 꺼내와서 쓸 수 있다. 보통 이러한 방법을 캐싱을 한다 라고 표현한다.
// useMemo 사용 전
const value = 반환할_함수();
// useMemo 사용 후
const value = useMemo(()=> {
return 반환할_함수()
}, [dependencyArray]);
const me = {
name: "Ted Chang",
age: 21,
isAlive: isAlive ? "생존" : "사망",
};
useEffect(() => {
console.log("생존여부가 바뀔 때만 호출해주세요!");
}, [me]);
useEffect의 의존성 배열에 me를 넣어서 me의 정보가 바뀌었을 때만 console.log가 찍히도록 코드를 썼다. 하지만 이 컴포넌트가 리렌더링될 때(me의 정보가 바뀌지 않았을 때)에도 console.log가 출력될 것이다. me는 타입이 객체라 리렌더링이 되면 주소값이 바뀌기 때문에 me의 값이 바뀌지 않아도 useEffect 안의 코드가 실행된다.
이를 막기 위해 useMemo를 쓸 수 있다.
const me = useMemo(() => {
return {
name: "Ted Chang",
age: 21,
isAlive: isAlive ? "생존" : "사망",
};
}, [isAlive]);
useMemo를 남발하게 되면 별도의 메모리 확보를 너무나 많이 하게 되기 때문에 오히려 성능이 악화될 수 있다. 필요할 때만 쓰는것이 좋다.