TIL[32일차] Memo해놓자! Memoization, 브라우저 렌더링 원리로 성능을 개선하자!

남예지·2022년 12월 13일
0

TIL

목록 보기
26/47

state 렌더링 원리

state를 쓰면 리렌더링이 되기 때문에 위에서 똑같은게 다시 만들어진다.

이렇게 state할때마다 재렌더링 되는건 불필요하다.

불필요한 재렌더를 막는 방법

  1. useMemo라는걸 사용한다.

사용법
useMemo(() => Math.random(), []){}
의존성배열안에 [] 있는게 바뀌지않으면 재렌더할때도 기존값을 기억만 하고 유지한다.

  • React.memo는 아예 렌더링을 시키지 않게 한다. 뒤에 해보겠다.
  1. 함수를 유지시키는건 useCallback이 있다.
    사용법
    const onClickCountState = useCallback(() => {
    console.log(countState + 1);
    setCountState(countState + 1);
    }, []);

마찬가지로 의존성 배열을 넣어준다.

그런데 이렇게 사용하는건 잘못된 사용법이다.
countState가 0일때를 기억해서 매번 1만 나오기 때문이다.

이때는 setCountState((prev) => prev + 1); 이렇게 해줘야한다.
이전값은 매번 달라지기 때문이다!

그럼 모든 컴포넌트에 memo를 달아버릴까?

모든 컴포넌트에 memo를 굳이 거는건 별로 안좋다.
컴퓨터는 메모를 다 따로 기록하는데 이런것들이 많아지면 오히려 느려져서 좋지못하다. 렌더링 될 이유가 없는 페이지만 메모를 거는게 좋다.

그리고 의존성배열이 많으면 오히려 유지보수에 안좋다.

브라우저 렌더링 CRP(Critical Rendering Path)

브라우저에 그림이 그려지려면 우선 프리렌더링을 거치고? 들어온 html, css, js 파일을 다운로드하고 html, css를 두개 합쳐 렌더트리를 브라우저에 그린다. 화면에 그려줄때 해당 요소들이 어느 위치에 놓일지 먼저 그려주는 Layout Reflow와 해당 요소들을 색칠하는 Paint Repaint과정이 발생한다.

CRP(Critical Rendering Path)이란

한국어로 중요한 렌더링 경로라고 한다.
브라우저가 HTML, CSS 및 JavaScript를 화면의 픽셀로 변환하기 위해 거치는 일련의 단계이다.
이를 최적화하면 렌더 성능이 향상된다.
DOM, CSSOM, 렌더링 트리 및 레이아웃이 포함된다.

  • DOM과 CSSOM이 합쳐진것이 바로 렌더트리(Render-tree)
  • 렌더트리를 배치하고 색칠하고 브라우저에 그린다.


Reflow와 Repaint with Board

우리가 목록을 조회해올 때 느린 화면으로 보면 데이터가 비었다가 나중에 들어오면서 UI가 울렁 거리는데 이는 브라우저가 렌더링 되면서 요소들이 화면에 위치를 잡으면서 나타나는 현상이다.
위치를 잡는 이 과정이 reflow이고, 위치를 잡고 난 후 색칠을 해주는 과정이 repaint이다.

이때 위치가 바뀌어 다시 그리게 되면 성능이 느리다. 왜냐하면 움직이 위치에 색도 다시 칠해야 되기 때문이다.
색칠보단 위치 그리기가 더 느림!!
나중에 복잡한 그림을 그릴때 성능을 개선해야할 때가 오면 이런걸 알고있어야 성능을 향상할 수 있으니 알고있으면 좋다.

Reflow with map

이게 울렁거리지 않게 하기 위해서는 height값을 잡아줘야 함!

{/* 임시 배열 10개를 생성하여, 데이터가 없을 때도 높이 30px을 유지하여 reflow */}
      {(data?.fetchBoards ?? new Array(10).fill(1)).map((el) => (
        <div key={el._id} style={{ height: "30px" }}>
          <span style={{ margin: "10px" }}>{el.title}</span>
          <span style={{ margin: "10px" }}>{el.contents}</span>
        </div>
      ))}

데이터를 뿌려주는 곳 height를 고정시키면 위치상으로 다시 그려야 하는 일이 없기 때문에 reflow가 일어나는 것을 방지 할 수 있다.


프리페치 (prefetch)

프리페치란?

다음페이지에서 쓰려고 미리받는 것이며, 현재페이지를 모두 받아온 이후 제일 나중에 다운로드 해오게 됩니다.
prefetch를 이용하면 페이지가 이동되어도 기다리지 않고 바로 보여주는 것이 가능하다.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <title>프리페치</title>

    <!-- 프리페치: 다음페이지를 미리 다운로드 받으므로, 버튼 클릭시 페이지이동 빠름 -->
    <link rel="prefetch" href="board.html" />
  </head>
  <body>
    <a href="board.html">게시판으로 이동하기</a>
  </body>
</html>

프리로드 (preload)

프리로드란?

현재 페이지에서 쓸 이미지들을 모두 다운로드 받아놓는 것 입니다.
프리페치와는 다릅니다!

<!DOCTYPE html>
<html lang="ko">
  <head>
    <title>프리로드</title>
    <link rel="stylesheet" href="./index.css" />
    <script src="./index1.js"></script>
    <script src="./index2.js"></script>
    <script src="./index3.js"></script>
    <script src="./index4.js"></script>
    <script src="./index5.js"></script>
    <script src="./index6.js"></script>
  </head>
  <body>
    <img src="./banner1.jpg" />
  </body>
</html>

이러면 이미지가 제일 늦게 받아와진다.

이 코드를 head 태그 안에 추가해 이미지를 먼저 다운받게 하자.

<link rel="preload" as="image" href="./banner1.jpg">

jS는 어차피 클릭하면 실행되니 나중에 받아와지게 하고 이미지를 먼저 받아오게 하면서 전체 모든 파일의 총 다운로드 시간이 더 짧아짐

이미지가 먼저 다운받아지는게 보임.

프리로드는...

  • 한번에 6개씩 받아오므로, body태그의 이미지는 가장 마지막에 다운로드 된다.
  • 눈에 보이는 이미지를 먼저 다운로드 받아서 보여주고, 클릭하면 실행되는 JS는 나중에 받아오기
  • 전체 모든 파일 총 다운로드 시간이 더 짧아짐
  • 프리페치는 다음을 위해서 받는 것이므로, 나중에 받음. 여기서 프리로드가 맞음

참고사이트
구글 페이지 스피드 인사이트
Page Speed Insights
-> 사이트의 속도가 어떤지 평가해줘서 성능 최적화를 할 때 사용

오늘 개념은 쉬우면서도 어렵다. 오늘 배운걸 기반으로 성능을 향상시킬수 있는 방향으로 생각하면서 코딩하는 습관을 만들어야겠다.

profile
총총

0개의 댓글