본문 바로가기

취업/면접

React.memo 알아보기 (feat. React.callback)

반응형

React.Memo

React.memo는 React 최적화할 때 사용하는 메소드이다. 사실 이것을 사용하지 않아도 React로 개발하는데 문제는 없지만, 속도를 개선하기 SPA를 위해서 사용하는 React 사용하는데 있어 React.Memo를 사용함을 통해 최적화를 한다면 좀 더 좋은 퍼포먼스를 통해 UX를 줄 수 있기에 사용을 할줄 알아야 어디가서 "React 해봤다~" 할 수 있다고 생각한다. 그리하여 이에 대해 정리해보도록 하자.

 

React는 React.Memo와 React.Callback과 묶여서 언급된다. 둘다 메모이제이션에 대해 관련된 메소드라 그런데 조금 더 자세히 알아보면 React.memo는 렌더링 결과를 메모이징하여 불필요한 Rendering을 건너뛴다.

 

메모이제이션이란 계산된 값을 자료구조에 저장하고 이후 같은 계산을 반복하지 않고 자료구조에서 꺼내 재 사용하는 것을 말한다. useMemo는 값을 반환하고, useCallback은 콜백을 반환한다.

 

React는 상태의 변경과 적절한 컴포넌트만 효율적으로 갱신하고 렌더링된다고 소개하지만, 실제로는 상태가 변경되는 컴포넌트와 그 이하의 모든 자식 컴포넌트가 렌더링의 대상이 된다. 여기서 문제는 상태가 변경되지 않아도(갱신될 필요가 없어도) 불 필요한 렌더링이 일어난다는 것이다.

 

// Text.jsx
const Text = ({title, value}) => <div>{title}:{value}</div>;
// Button.jsx
const Button = ({ handleClick, children }) => <button onClick={handleClick}>{children}</button>;
// Name.jsx
const Name = () => <div>홍길동</div>;

// BodyProfile.jsx
const BodyProfile = () => {
  const [weight, setWeight] = useState(0);
  const incrementWeight = () => setWeight(weight + 1);

  const [height, setHeight] = useState(0);
  const incrementHeight = () => setHeight(height + 1);

  return(
    <>
      <Name/>
      <Text title="weight" value={weight}/>
      <Button handleClick={incrementWeight}>몸무게 증가</Button>
      <Text title="height" value={height}/>
      <Button handleClick={incrementHeight}>키 증가</Button>
    </>
  );
}

 

예시를 들어보자. 위의 코드는 Text, Button, Name이 컴포넌트로 만들어져서 BodyProfile 컴포넌트에서 사용되어 return 된다. Text, Button, Name은 BodyProfile이 변경되고 리 렌더링 될때마다 재 렌더링된다. 이를 메모이제이션을 통해 성능 최적화를 할 수 있다.

그래서 위 컴포넌트들을 React.memo를 사용해보면

 

export default React.memo(Name);
export default React.memo(Text);
export default React.memo(Button);

 

이러면 Name 컴포넌트는 더 이상 불필요한 렌더링이 발생하지 않는다. 하지만 Button 재 렌더링 되는데 이는 props로 전달되는 handleClick함수때문이다.

 

function sumFactory() {
  return (a, b) => a + b;
}

const sum1 = sumFactory();
const sum2 = sumFactory();

console.log(sum1 === sum2); // => false
console.log(sum1 === sum1); // => true
console.log(sum2 === sum2); // => true

 

위 코드를 이해하면 쉽게 이해가 되는데 sum1 과 sum2는 같지 않다. 메모리에 저장되는 위치가 다르기 때문에 같은 역할을 하는 함수라도 같지 않은 것이다. 그래서 handleClick의 함수가 매번 다른 함수로 인식되어 호출을 하는 것인데 이를 위해 React.useCallback을 사용하면 된다.

 

const incrementHeight = useCallback(() => {
  setHeight(height + 1);
}, [height]);

const incrementWeight = useCallback(() => {
  setWeight(weight + 1);
}, [weight]);

 

useCallback은 콜백 함수를 메모이제이션하여, 오직 의존하는 상태값이 변경된 경우에만 갱신된다. useEffect와 마찬가지로 두번째 인수를 비교하고 싶은 상태값을 넣어주면된다.

 

useMemo를 통해서도 함수를 메모이제이션하는 척을 할 수 있는데 이는 useCallback과는 다르다. useMemo를 사용하면 전달된 함수가 실행되고 반환된 결과를 캐싱한다는 것이다. 이는 참고 항목에서 확인하길 바란다.

 

useMemo에 전달된 함수는 렌더링 중에 실행되기 때문에 렌더리이과 관련된 작업을 전달하는 것이 적절하다.

 

그렇다면 useMemo를 사용할 때 조심해야할 점은 무엇일까?

  1. Class형 컴포넌트서 사용하지 않는다.
  2. 일단 React.memo는 React Hooks에서 사용하도록 고안된 Hook이다. class형 컴포넌트에서도 사용할 수 있지만 PureComponent를 확장하거나, sholudComponentUpdate() 메서드를 구현하는 것이 적절하다.
  3. 쓸모없는 props 비교
  4. 렌더링 될 때마다 props가 다른 경우 React.memo를 사용할 필요가 없다. 불필요한 비교를 하게 되고 성능상 이점을 가져오기는 커녕 성능저하를 일으킨다.

React.memo는 성능 개선의 도구이다. 메모이징 된 컴포넌트의 리렌더링을 피할 순 있지만 렌더링을 막기위해 메모이 제이션에 의존하면 안된다. 콜백함수를 prop으로 사용하는 컴포넌트에서 메모이징에 주의하자.

참고

React.meme() 현명하게 사용하기 - Toast UI

React Hooks: 메모이제이션 훅 (useMemo, useCallback)

반응형

'취업 > 면접' 카테고리의 다른 글

Promise 면접질문  (0) 2022.02.14
지긋지긋한 CORS! 타파!!  (0) 2021.10.16
Callback 비교 - 1  (0) 2021.08.07
React 배열에 key가 존재하는 이유  (0) 2021.08.06
CSS in JS vs CSS  (0) 2021.08.05