React에서 성능 최적화는 불필요한 렌더링을 줄이고 렌더링 속도를 높이는 것을 목표로 함
React는 기본적으로 빠르게 렌더링 되지만, 컴포넌트가 많아지거나 상태가 복잡해지면 최적화가 필요함
useMemo
, useCallback
, React.memo
는 성능 최적화를 위한 도구로, 불 필요한 계산이나 렌더링을 방지하여 앱의 렌더링 성능을 개선할 수 있음
메모이제이션
컴포넌트가 불필요하게 다시 계산하거나 렌더링하는 것을 방지하기 위해 이전에 계산한 값을 저장해두고 재사용하는 기법
컴포넌트가 특정 상태나 props가 변경되지 않으면, 이미 저장된 값이나 함수를 재사용하여 성능을 최적화 할 수 있음
useMemo: 값 메모이제이션
- 역할: useMemo는 비용이 많이 드는 연산(복잡한 계산)이나 함수 결과를 메모이제이션하여, 특정 상태나 Props가 변경될 때만 다시 계산하고 그렇지 않으면 이전 값을 재사용함
- 사용법: 연산 결과를 저장하고, 지정된 의존성 배열의 값이 변경될 때만 새로 계산
예제: 배열의 큰 값 찾기
import React, { useState, useMemo } from 'react';
function ExpensiveComponent({ numbers }) {
// useMemo로 메모이제이션하여 numbers가 변경될 때만 계산
const largestNumber = useMemo(() => {
console.log("복잡한 연산 실행 중...");
return Math.max(...numbers);
}, [numbers]);
return <div>가장 큰 수: {largestNumber}</div>;
}
export default function App() {
const [numbers] = useState([10, 20, 300, 400, 500]); // numbers는 변하지 않음
const [counter, setCounter] = useState(0);
return (
<div>
<button onClick={() => setCounter(counter + 1)}>카운터 증가</button>
<ExpensiveComponent numbers={numbers} />
<p>카운터: {counter}</p>
</div>
);
}
largestNumber
는 numbers
배열이 변경되지 않는 한 새로 계산되지 않고, 이전 결과를 재사용 함
numbers
가 변경될 때만 Math.max(...numbers)
실행
이로써 counter
가 변경되어도 findLargestNumber
는 재실행되지 않아 불필요한 계산을 피하고 성능을 최적화할 수 있음
useCallback: 함수 메모이제이션
- 역할: useCallback은 함수의 참조값을 메모이제이션하여, 컴포넌트가 리렌더링될 때마다 새로생성되지 않도록함
- 특히 자식 컴포넌트에 콜백 함수를 props로 전달할 때 유용
- 사용법: 함수의 참조를 저장하고, 지정된 의존성 배열의 값이 변경될 때에만 새로 생성
예제: 자식 컴포넌트에 전달되는 콜백 함수 메모이제이션
import React, { useState, useCallback } from 'react';
function ChildComponent({ onClick }) {
console.log("자식 컴포넌트 렌더링");
return <button onClick={onClick}>카운터 증가</button>;
}
export default function App() {
const [counter, setCounter] = useState(0);
// useCallback을 사용하여 onClick 함수 메모이제이션
const handleClick = useCallback(() => {
setCounter(prev => prev + 1);
}, []);
return (
<div>
<p>카운터: {counter}</p>
<ChildComponent onClick={handleClick} />
</div>
);
}
handleClick
은 useCallback
을 통해 메모이제이션되어 컴포넌트가 리렌더링될 때마다 새로 생성되지 않음
이로써 onClick
prop(handleClick)의 참조값이 변경되지 않으므로, ChildComponent
는 불필요하게 리렌더링되지 않음
React.memo: 컴포넌트 메모이제이션
- 역할: React.memo는 컴포넌트를 메모이제이션하여, props가 변경되지 않는 한 컴포넌트를 다시 렌더링하지 않도록 함
- 사용법: 컴포넌트를 React.memo로 감싸면 props가 변경되지 않는 경우 해당 컴포넌트는 리렌더링되지 않음
자식 컴포넌트가 부모 컴포넌트의 리렌더링과 무관하게 불필요하게 리렌더링되는 문제를 해결할 수 있음
예제: React.memo로 불필요한 렌더링 방지하기
import React, { useState, memo } from 'react';
// React.memo로 ChildComponent 메모이제이션
const ChildComponent = memo(({ count }) => {
console.log("자식 컴포넌트 렌더링");
return <div>카운트: {count}</div>;
});
export default function App() {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
return (
<div>
<ChildComponent count={count} />
<button onClick={() => setCount(count + 1)}>카운트 증가</button>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="텍스트 입력"
/>
</div>
);
}
ChildComponentsms
는 React.memo
로 감싸져 있으므로, count
가 변경될 때만 다시 렌더링 됨
text
상태가 변경되어도 count
가 동일한 경우 ChildComponent
는 다시 렌더링되지 않음
React.memo와 memo는 동일한 기능을 제공!
memo는 React객체에서 직접 꺼내온 React.memo의 약식 표현임
요약
- useMemo: 값의 메모이제이션
- 비용이 많이 드는 연산을 메모이제이션하여, 의존성(props) 변경 시에만 새로 계산되도록 함
- useCallback: 함수의 메모이제이션
- 함수 참조값을 메모이제이션(유지)하여, 자식 컴포넌트의 불필요한 렌더링을 방지함
- React.memo: 컴포넌트의 메모이제이션
- props가 변경되지 않는 한 컴포넌트를 다시 렌더링하지 않음
'FE > React & Redux' 카테고리의 다른 글
React | 함수형 컴포넌트 생명주기와 useEffect (0) | 2024.10.30 |
---|---|
React | 클래스형 컴포넌트 생명주기 (0) | 2024.10.30 |
React | 상태관리와 useState (0) | 2024.10.29 |
React | State와 Props 데이터 관리 (0) | 2024.10.29 |
React | Redux Toolkit 전역 상태 관리 (0) | 2024.10.28 |