[개념정리] useMemo, useCallback, React.memo의 사용

2021. 1. 11. 12:25프로그래밍-Web/React

<useMemo>

 

- CASE: 특정 상황에서만 동작되어야 하는 함수가, Component의 렌더링 조건에 따라 지속적으로 함수가 실행되는 경우

 

예시

이런 경우.

countActiveUser는 users가 변화가 있을때만 다시 실행되어야 하는데, 예시코드처럼 로직을 짜면 모든 state변화마다 count가 다시 호출되어 실행된다.

 

이러한 경우에 useMemo를 사용한다. useEffect와 사용법은 유사하다. useMemo의 동작조건을 설정하고, 그 변수에 내가 원하는 상황을 등록해주면 된다.

 

- useRef와의 차이

 

useMemo는 deps가 변경되기 전까지 값을 기억하고, 실행후 값을 보관하는 역할로도 사용한다. 얘는 복잡한 함수의 return 값을 기억한다는 점에서 useRef와는 다르다. useRef는 특정 값을 기억하는 경우, useMemo는 복잡한 함수의  return값을 기억하는 경우에 사용한다.

 

 

<useCallback>

 

- CASE : useMemo가 특정 value를 재사용하기 위함이라면, useCallback은 특정 함수를 재사용하기 위함이다.

 

useMemo와 유사하게(사실 useCallback자체가 useMemo기반의 로직) 각 함수마다 useCallback으로 정의하고 조건을 달아주면 된다. 당연하게도 해당 조건들은 함수내에서 사용하는 모든 변수여야 할 것!

 

자식컴포넌트에 함수를 props으로 줄때는 반드시 useCallback을 사용하여 리렌더링이 안되도록 하자.

 

 

<React.Memo>

 

기본적으로 리액트는 Shallow copy를 실행한다(참조값만 비교)

즉, state가 변경되거나, 새로운 컴포넌트가 렌더링 되는 시점에서, Shallow copy를 통해 같은값인지 판단하고 렌더링 여부를 결정하게 된다.

그렇기 때문에 primitive type이 아닌 객체,배열,함수와 같은 reference type은 같은 참조가 아니라면 새로운 값으로 판단하게 된다. 

예컨데 같은 값의 props라도 컴포넌트의 state가 변경되면  shallow copy에 의해 새로운 값으로 인식하는 것이다.

props 자체는 primivite type이기 때문에 값만 같아도 될지언정, 함수나 객체는 그렇지 않다. 

그러므로 useCallback, useMemo를 통해 특정 props에 dependency를 걸어줌으로써 렌더링 횟수를 줄일 수 있다.

 

그러나!

useCallback만으로는 하위컴포넌트의 리렌더링을 막을 수 없다.

부모 컴포넌트에서 정의한 useCallback은 자식 컴포넌트에서 사용할때 아무 효력도 없기 때문이다.

자식 컴포넌트에 useCallback에 대한 로직처리가 없다면, 다시 부모의 렌더링 여부에 따라 렌더링 될 뿐이다.

즉, 자식 컴포넌트가 '참조동일성에 의존적인 pureComponent여야 의미가 있다. 

 

장황했던 위의 방식은 자식 컴포넌트에 대한 React.memo 처리로 끝이다.

얘는 일종의 HOC인데, shouldComponentUpdate를 내장하고 있어 shallow copy를 실행하여 리렌더링을 방지한다.

 

방법적으론 예시코드 처럼 모듈화 시키는 컴포넌트를 export할때 React.memo로 감싸주면 된다.

이 방식은 '같은 props로 렌더링이 자주일어나는 컴포넌트','렌더링에 리소스 소모가 큰 컴포넌트'에 사용된다

그러나 무분별하게 사용되는 것은 좋지 않다. 어떠한 경우에는 그저 불필요한 비교 연산만 추가되는 꼴이 되기 때문이다. 

 

얕은 비교를 원하지 않는 경우 customizing이 가능하다. 

React.memo는 false일 경우에만 리렌더링이 된다.(shouldComponentUpdate는 true일때 렌더링을 허용한다는 점이 다르다)