학습내용
- React.memo
- useCallback
- useMemo
캐싱 대상을 기억한 후 필요할 때마다 재사용해서 불필요한 렌더링이 발생하지 않도록 최적화 하는 작업
memoization의 종류
- | React.memo | useCallback | useMemo |
---|---|---|---|
캐싱 대상 | 컴포넌트 | 함수 | 값 |
자식 컴포넌트의 리렌더링 발생 조건
1. state
가 변경되었을 때
2. props
가 변경되었을 때
3. 부모 컴포넌트가 리렌더링 되었을 때
부모 컴포넌트가 리렌더링 되었을 때 자식 컴포넌트까지 불필요하게 리렌더링 되는 일을 방지하기 위해 컴포넌트를 기억
App.jsx
const App = () => {
const [count, setCount] = useState(0);
const onPlusClick = () => {
setCount(count + 1);
}
count onMinusClick = () => {
setCount(count - 1);
}
return(
<>
<h3>{count}<h3>
<button onClick={onPlusClick}>+</button>
<button onClick={onMinusClick}>-</button>
<Box1 />
<Box2 />
<Box3 />
</>
);
}
위 예제에서 +
,-
버튼을 클릭하면 <Box />
컴포넌트들은 state
가 변하지 않았음에도 불구하고 리렌더링이 발생한다.
export default React.memo(Box1);
이 경우 자식 컴포넌트를 export
할 때 React.memo
를 사용하면 해당 컴포넌트를 기억하기 때문에 불필요한 리렌더링이 일어나지 않는다. 혹은 아래와 같이 사용할 수도 있다.
import { memo } from "react";
.
.
.
export default memo(Box1);
단, React.memo
가 모든 경우에 적용되는 것은 아니다. 자식 컴포넌트가 가벼운 작업을 수행할 경우에는 사용하지 않는 것이 성능면에서 좋다.
함수의 내용은 변하지 않았으나 주소값이 변경돼서
props
변경으로 불필요한 리렌더링이 일어나는 일을 방지하기 위해 함수를 기억
<Box1/>
안에 count
를 초기화 하는 버튼을 생성하고 초기화를 실행 시키는 함수 initCount()
를 App.jsx에서 내려준다고 가정해보자. 초기화 버튼을 실행하면 App과 Box1이 모두 리렌더링 된다. 부모 컴포넌트가 리렌더링 됨에 따라 발생한 리렌더링은 React.memo
로 방지하고 있기 때문에 이 경우엔 props
가 변경된 경우에 해당한다.
const initCount = () => {
setCount(0);
};
props
로 받아오고 있는 initCount
는 변하지 않는 함수다. 그러나 함수는 객체에 해당한다. 자바스크립트는 객체 저장시 객체의 내용이 아니라 주소를 저장한다. 그래서 내용이 같은 두 객체가 있다면 그 둘은 실제로 다른 객체에 해당된다. 마찬가지로 App이 렌더링 될 때마다 initCount
를 다른 주소에 할당하고 있기 때문에 Box1에서 리렌더링이 일어나는 것이다.
const initCount = useCallback(() => {
setCount(0);
}, []);
이처럼 함수의 내용이 변하지 않는 경우 위와 같이 useCallback
을 사용하면 불필요한 리렌더링을 방지할 수 있다. 단, 최초 렌더링시 저장된 값만을 기억하기 때문에 특정 값이 변화할 때마다 반영하기 위해선 useEffect
와 마찬가지로 의존성 배열에 해당 state
를 추가한다.
객체, 배열, 함수의 값을 저장해서 불필요한 작업 방지
Box2.jsx
const Box2 = () => {
const [count, setCount] = useState(0);
const heavyWork = () => {
for(i = 0; i < 5000000000; i++){
//
}
return 100;
};
const value = heavyWork();
return(
<>
<h2>{value}</h2>
<button onClick={() => {setCount(count+1);}}>클릭</button>
<p>{count}></p>
</>
);
}
count
가 변할 때마다 heavyWork
를 실행한다. 그러나 heavyWork
는 늘 100을 return 하기 때문에 매번 실행을 할 필요가 없으므로 불필요한 작업이 발생한다.
const value = useMemo(() => heavyWork(), []);
useMemo
를 사용하면 최초 렌더링시에만 값을 저장해서 불필요한 작업을 방지할 수 있다. 마찬가지로 의존성 배열을 사용한다.