React

최적화 - React.memo, useCallback, useMemo

차돌박이츄베릅 2023. 6. 20. 11:08

리-렌더링의 발생 조건

  1. 컴포넌트에서 state가 바뀌었을 때
  2. 컴포넌트가 내려받은 props가 변경되었을 때
  3. 부모 컴포넌트가 리-렌더링 된 경우 자식 컴포넌트는 모두 


최적화하는 방법

  • memo(React.memo) : 컴포넌트를 캐싱
  • useCallback: 함수를 캐싱
  • useMemo: 값을 캐싱(함수가 리턴하는 값이나 값 자체)

 

 

 


1. memo

컴포넌트를 '메모리'에 저장(캐싱)해두고 필요할 때 갖다 씀.
이렇게 하면 부모 컴포넌트의 state가 변경으로 인해 props가 변경이 일어나지 않는 한 컴포넌트는 리렌더링 되지 않음

하위 컴포넌트를 export하는 부분에서 React.memo()로 감싸줌

export default React.memo(Box1);
export default React.memo(Box2);
export default React.memo(Box3);



 


2. useCallback

인자로 들어오는 함수 자체를 메모이제이션(기억)한다.

우리가 함수형 컴포넌트를 사용하는데,

함수도 객체의 한 종류라서 다시 리렌더링되면 다시 만들어지면서 그 주소값이 달라짐.

그래서 하위컴포넌트에서는 props가 변경됐다고 인식해서 하위 컴포넌트도 리렌더링 됨

 

(예시)

App.jsx처음 렌더링될때 initCount함수를 모양 그대로 저장한거. 의존성 배열에 아무것도 없기 때문에 변하지 않고(갱신X) 그대로 남아있음. 그때 당시의 snapshot 그대로.

const initCount = useCallback (() => {
  setCount(0);
}, []);

 

그래서 의존성 배열을 이용해 state가 변경될 때마다 다시 실행하도록 아래처럼 해줘야함

const initCount = useCallback (() => {
  console.log(`${count}에서 0으로 변경`)
  setCount(0);
}, [count]);

 

 

 


3. useMemo

동일한 값을 반환하는 함수를 계속 호출해야 하는 경우 필요없는 렌더링을 하게 됨.

맨 처음 해당 값을 반환할 때 그 값을 특별한 곳(메모리)에 저장해놓고,

필요할 때 마다 다시 함수를 호출해서 계산하는게 아니라

이미 저장한 값을 단순히 꺼내와서 쓸 수 있음.

 

dependencyArray의 값이 변경될 때만 반환할함수()가 호출 됨

const value = useMemo(() => {
  return 반환할함수()
}, [dependencyArray]);


리렌더링 시

중간에 껴 있는 무거운 함수때메 렌더링이 느려질때
useMemo를 사용하면 좋음.

한번 리턴해놓은 값을 저장해놓고 변할 때까지 계속 씀

const value = useMemo(() => heavyWork(), []);

 

(예제 코드의 문제점) - 객체가 바뀌지 않았는데도 계속 호출 됨

객체베이스(객체, 배열, 함수)로 저장해놓은 부분이
다시 그려지면서 메모리주소가 바뀌기때문에
리엑트에서는 이전값과 달라졌다고 인식하여 useEffect가 발동이 되었음

const [isAlive, setIsAlive] = useState(true);
... 
const me = {
  ...
  isAlive: isAlive ? '생존' : '사망',
}
...
// 여기가 me가 안바꼈는데도 계속 호출됨
useEffect(()=>{console.log('생존여부가 바뀔때만 호출해줘')}, [me]);
...
onClick={()=>{
setIsAlive(!isAlive);
}}

 

 

(해결책)

그래서 이때 useMemo를 다시 활용할 수 있음.
객체를 할당할때 useMemo훅을 이용해 추가로 감싸주면 됨

const me = useMemo(()=>{
  return {
  ...
  isAlive: isAlive ? '생존' : '사망',
};
}, [isAlive]);



메모리 확보하느라 성능이 안좋아질 수 있기 떄문에 필요할 때만 쓰자!