React/know

최적화를 위해 필요한 기능 memo, useMemo, useCallback

타코따코 2024. 11. 13. 21:17

성능 최적화(1) : memo, useMemo, useCallback

  • React.memo : setState에 의해 랜더링 되는 경우, react.memo로 파싱되는게 원초적인 값이라면, 해당 하위 컴포넌트는 리랜더링 되지 않는다.
    • setState에 의해 해당 ParentComponent가 새롭게 생성 → 해당 컴포넌트 랜더링
    • ChildComponent도 리랜더링, → 하지만 setState에 의해 ChildComponent가 변경될 필요가 없다면
    • memo를 사용해서 리랜더링 방지가 가능하다. (이전 값 계속 사용)
    • 장점 : 캐싱 사용 → 리랜더링 방지 → 속도 향상
    • 단점 : 값(string, boolean..)과 같은 원초적인 값만 적용, {}와 같은 객체 전달시 캐싱이 불가능
    • 이유 : 모두 새롭게 생성 → 새로운 객체를 생성 → 이전과 다른 참조값 → 다르게 인식 → 다시 인식
    const ParentComponent = () => {
      const [data, setData] = useState({ text: "Hello" });
    
      return (
        <div>
          <button onClick={() => setData({ text: "Hello" })}>Update Data</button>
          <ChildComponent data={data} />
        </div>
      );
    };
    
    const ChildComponent = **React.memo**(
      ({ data }) => {
        console.log("Child component rendered!");
        return <div>Data: {data.text}</div>;
      },
      (prevProps, nextProps) => prevProps.data.text === nextProps.data.text
    );
    
    이렇게 하면 Hello라는 값이 바뀌지 않는 한 ChildComponent은 리랜더링 되지 않는다. 
    
     

 

useMemo : 주소값이 아닌 객체값으로 비교해서, 해당 값을 캐싱해서 사용 → 성능 최적화

  • 원초값만 캐싱이 가능한 memo의 한계를 처리.
  • 주소값 비교가 아닌 객체들의 값으로 비교, 값이 같다면 캐싱된 값을 그대로 사용
  • posts.length가 변하기 전까지 이 객체를 캐싱해서 계속 사용
const archiveOptions = useMemo(() => {
	return {
		show:false,
		title: 'hello world'
	};
}, [posts.length]
}

 

useCallback : 컴포넌트 랜더링 시 → 함수도 재생성 → 리소스 많이 드는 함라면 useCallback으로 의존배열이 변경할때만 재생성 되도록 한다.

  • ParentComponent 리랜더링시 handleIncrement 함수도 다시 생성
  • useCallback을 사용해서 handleIncrement의 변경은 count에 의존하도록 변경
  • handleIncrement의 무의미한 재생성을 방지가능.
import React, { useState, useCallback } from 'react';

const ChildComponent = React.memo(({ onButtonClick }) => {
  console.log('Child component rendered');
  return <button onClick={onButtonClick}>Increment from Child</button>;
});

const ParentComponent = () => {
  const [count, setCount] = useState(0);

  // count가 변경될 때만 새로운 함수가 생성됨
  const handleIncrement = **useCallback**(() => {
    setCount((prevCount) => prevCount + 1);
  }, [**count**]);

  return (
    <div>
      <p>Count: {count}</p>
      <ChildComponent onButtonClick={handleIncrement} />
    </div>
  );
};

export default ParentComponent;

 

 

언제 memo, useMemo, useCallback을 쓸까?

  • React DevTools의 “Components” 탭을 통해 불필요하게 재렌더링되는 컴포넌트를 확인
  • Chrome DevTools나 React Profiler를 사용해 렌더링 성능과 속도 저하의 원인을 파악
  • 프로파일러에서 컴포넌트 렌더링 시간과 횟수를 살펴보고, 성능 병목이 되는 지점을 발견
  • 처음부터 최적화를 하려고 하지 말자. 

'React > know' 카테고리의 다른 글

성능 최적화 : React Dev Tool, React.lazy  (2) 2024.11.19
useEffect 알아보기  (0) 2024.11.18
useRef 알아보기  (0) 2024.11.17
useState에 대해 정리해보기  (1) 2024.11.15
Key는 왜 쓰는 걸까?  (0) 2024.11.13