소개
리액트에서 컴포넌트의 성능 최적화는 항상 중요한 고려사항 중 하나입니다.
React.memo는 함수형 컴포넌트의 성능을 향상시키기 위한 효과적인 방법 중 하나로,
이 글에서는 React.memo의 개념, 사용법, 그리고 주의사항에 대해 간단히 알아보겠습니다.
1. React.memo란?
React.memo는 리액트에서 제공하는 특별한 고차 컴포넌트로,
컴포넌트의 랜더링 결과를 메모이제이션(Memoization)하여 성능을 최적화하는 역할을 합니다.
이를 통해 랜더링이 불필요하게 발생하지 않아 성능 향상이 기대됩니다.
기본적인 사용법은 다음과 같습니다.
const MemoizedComponent = React.memo(MyComponent);
위 코드에서 MyComponent는 React.memo에 의해 메모이제이션되어,
같은 props로 여러 번 랜더링되더라도 결과가 이전에 계산된 값과 동일하다면
실제로 렌더링이 발생하지 않습니다.
2. React.memo의 사용법
2.1. 기본 사용
가장 기본적인 형태로 React.memo를 사용하는 방법은 아래와 같습니다.
import React from 'react';
const MyComponent = ({ data }) => {
// 컴포넌트의 렌더링 로직
};
const MemoizedComponent = React.memo(MyComponent);
MyComponent가 React.memo에 의해 메모이제이션되어 MemoizedComponent가 생성됩니다.
따라서 생성된 MemoizedComponent 컴포넌트를 가져다 쓰시면 됩니다.
아래 처럼 쓸 수도 있습니다.
const CounterA = React.memo(({ count }) => {
useEffect(() => {
console.log(`CounterA Update - count : ${count} `);
});
return <div>{count}</div>;
});
위 코드에서 CounterA 컴포넌트의 props인 count가 변경되지 않는다면
그 값이 메모이제이션되어 CounterA 컴포넌트는 리랜더링되지 않습니다.
함수형 컴포넌트를 작성할 때 바로 React.memo로 감싸준 케이스입니다.
이렇게 해주면 CounterA를 바로 가져다 쓸 수 있습니다.
2.2. 커스텀 비교 함수 사용
React.memo는 기본적으로 얕은 비교(Shallow Comparison)를 수행합니다.
그러나 복잡한 객체나 배열을 다루는 경우에는 정확한 비교를 위해
커스텀 비교 함수를 제공할 수 있습니다.
예를 들어서
const A = {data:1};
const B = {data:1};
일 때 A===B는 false입니다.(실제로 다른 객체이고 주소 값을 비교하기 때문입니다.)
이럴 때 React.memo의 두번 째 인자로 비교 함수를 제공합니다.
import React from 'react';
const MyComponent = ({ complexData }) => {
// 컴포넌트의 렌더링 로직
};
const areEqual = (prevProps, nextProps) => {
return prevProps.complexData === nextProps.complexData;
};
const MemoizedComponent = React.memo(MyComponent, areEqual);
이렇게 하면 complexData가 변경되었을 때에만 렌더링이 수행됩니다.
다른 코드로 한번 더 보겠습니다.
import React, { useEffect, useState } from "react";
const CounterB = ({ obj }) => {
useEffect(() => {
console.log(`CounterB Update - count : ${obj.count} `);
});
return <div>{obj.count}</div>;
};
const areEqual = (prevProps, nextProps) => {
/* if (prevProps.obj.count === nextProps.obj.count) {
return true; // 이전 props와 현재 props가 같다 -> 리랜더링X
}
return false; // 이전 props와 현재 props가 다르다 -> 리랜더링O*/
return prevProps.obj.count === nextProps.obj.count;
};
const MemoizedCounterB = React.memo(CounterB, areEqual);
const OptimizeTest = () => {
const [obj, setObj] = useState({
count: 1,
});
return (
<div style={{ padding: 50 }}>
<div>
<h2>Counter B</h2>
<MemoizedCounterB obj={obj} />
<button
onClick={() =>
setObj({
count: obj.count,
})
}
>
B button
</button>
</div>
</div>
);
};
export default OptimizeTest;
위의 코드에서는
B button을 눌렀을 때 obj의 count가 동일한 값으로 변경이 됩니다.
똑같은 값이라 단순하게 생각해서
CounterB 컴포넌트를 React.memo로만 감싸게 되면 원하는 리랜더링 방지가 되지 않습니다.
몇번이고 리랜더링이 됩니다.
실제로 객체가 바뀌었고(주소 자체가 다름) 얕은 비교를 통해 잡아낼 수 없습니다.
따라서 areEqual이라는 비교 함수를 커스텀하여 React.memo의 두번째 인자로 전달 후에
새로운 MemoizedCounterB 컴포넌트를 사용해야 합니다.
그렇게 하면 리랜더링을 방지할 수 있습니다.
3. 주의사항
3.1. 함수 컴포넌트에만 적용 가능
React.memo는 함수 컴포넌트에만 적용 가능합니다.
클래스 컴포넌트에서는 shouldComponentUpdate 메서드 등을 활용해 수동으로 최적화를 해야 합니다.
3.2. 얕은 비교
React.memo의 기본 동작은 얕은 비교입니다.
따라서 복잡한 객체나 배열의 경우에는 주의가 필요하며,
필요하다면 커스텀 비교 함수를 활용해야 합니다.
3.3. 성능 측정
React.memo를 사용하여 성능을 최적화하려면 실제로 성능 측정을 수행해야 합니다.
컴포넌트의 규모와 랜더링 주기 등을 고려하여 성능 향상 여부를 확인해보세요.
4. React.memo의 활용
4.1. 리스트 아이템 최적화
React.memo는 리스트 아이템처럼 여러 번 반복되는 컴포넌트의 랜더링을 최적화하는 데에 매우 유용합니다.
import React from 'react';
const ListItem = ({ item }) => {
// 리스트 아이템의 렌더링 로직
};
const MemoizedListItem = React.memo(ListItem);
const List = ({ data }) => {
return (
<ul>
{data.map((item, index) => (
<MemoizedListItem key={index} item={item} />
))}
</ul>
);
};
4.2. 랜더링 비용이 높은 컴포넌트 최적화
렌더링 비용이 높은 컴포넌트에 React.memo를 적용하여,
해당 컴포넌트가 필요할 때만 렌더링되도록 최적화할 수 있습니다.
마무리
React.memo는 리액트에서 함수형 컴포넌트의 성능을 최적화하는 강력한 도구입니다.
주의사항을 잘 숙지하고, 적절한 상황에서 활용하여 랜더링 성능을 향상시키는 데에 활용해보세요.
함수형 컴포넌트를 사용하는 프로젝트에서는
특히 리스트 아이템과 랜더링 비용이 높은 컴포넌트에 적극적으로 적용할 수 있습니다.
'React' 카테고리의 다른 글
리액트의 SPA와 CSR 방식 (0) | 2024.01.15 |
---|---|
리액트의 useReducer: 컴포넌트에서 상태변화 로직을 분리 (1) | 2024.01.03 |
리액트의 useMemo: 성능 최적화(연산 결과 재사용) (1) | 2024.01.02 |
React에서 API호출(fetch 사용) (0) | 2024.01.01 |
리액트의 useEffect로 컴포넌트 생명주기 관리하기 (0) | 2024.01.01 |