패스트캠퍼스/React&Redux

[패스트캠퍼스] 프론트엔드 강의 학습일지(React 앱 성능 개선)

Rosie, Lee 2023. 4. 25. 01:16

국비지원교육으로 패스트캠퍼스에서 진행하는 프론트엔드 강의를 듣고 정리한 내용입니다.


리액트 확장 프로그램

https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=ko 

 

React Developer Tools

Adds React debugging tools to the Chrome Developer Tools. Created from revision 28ce1c171 on 3/22/2023.

chrome.google.com

 

Profiler 성능 측정을 위한 테스트

위에서 설치한 확장프로그램에서 Profiler 기능을 확인해 보기 위해 앱을 만들어 본다.

데이터가 많아야 확인이 가능하기 때문에 가짜 데이터를 가지고 와서 사용해 본다.

 

가짜 데이터 API를 사용할 수 있는 곳

https://jsonplaceholder.typicode.com/

 

JSONPlaceholder - Free Fake REST API

{JSON} Placeholder Free fake API for testing and prototyping. Powered by JSON Server + LowDB. Tested with XV. Serving ~2 billion requests each month.

jsonplaceholder.typicode.com

 

A컴포넌트: 모든 요소를 하나의 컴포넌트에 넣음 | B컴포넌트: 여러 컴포넌트로 나누어줌

Pfofiler로 성능 측정했을 때 A컴포넌트가 1.3ms, B컴포넌트가 2.8ms로 나누지 않은 게 성능이 더 좋게 나왔다.

 

이유는 input에 작성하는 글만 렌더링 되어야 하는데, 리스트까지 모두 렌더링이 되고 있었다.(확장프로그램의 Components -> Highlight updates when components render 를 체크하면 확인할 수 있다.)

즉 렌더링 되지 않아도 되는 부분까지도 렌더링이 돼서 성능이 안 좋게 나왔다.

React.memo

위 문제가 있는 B 컴포넌트를 React.memo로 성능 최적화를 해본다.

import React from 'react';

const ListItem = React.memo(({ post }) => {
  return (
    <li key={post.id}>
      <p>{post.title}</p>
    </li>
  );
});

const List = React.memo(({ posts }) => {
  return (
    <ul>
      {posts.map((post) => (
        <ListItem
          key={post.id}
          post={post}
        />
      ))}
    </ul>
  );
});

const Message = React.memo(({ message }) => {
  return <p> {message} </p>;
});

const B = ({ message, posts }) => {
  return (
    <div>
      <h1>B components</h1>
      <Message message={message} />
      <List posts={posts} />
    </div>
  );
};

export default B;

위 코드와 같이 수정하고 처음과 같은 방식으로 테스트했는데, A는 1.7ms, B는 0.1ms로 성능이 좋아졌다.

React.memo() 란?

컴포넌트가 React.memo()로 둘러 쌓여 있다면, 처음 컴포넌트를 렌더링 하고 결과를 메모이징(Memoizing)한다.

그리고 다음 렌더링 시 Props가 같으면 메모이징 된 내용을 재사용한다.

Memoization은 주어진 입력 값에 대한 결과를 저장함으로써 같은 입력값에 대해 함수가 한 번만 실행(캐시 된 결과를 반환)해서 컴퓨터 프로그램 속도를 높이는데 주로 사용되는 최적화 기술입니다.

React.memo()를 사용할 때는 Profiler를 통해 성능 개선의 여지가 있을 경우에 사용한다. 너무 의존하면 버그 유발 가능성이 있다.

 

 

얕은 비교

숫자, 문자열 등 원시 자료형은 값을 비교한다.

배열과 객체 등 참조 자료형은 참조되는 위치를 비교한다.

 

얕은 비교가 사용되는 경우

  • React.memo()
  • state 변경이 있을 때
  • 부모 컴포넌트가 렌더링 될 때

 

참고) 리액트가 리렌더링 되는 경우

  • state 변경이 있을 때
  • 부모 컴포넌트가 렌더링 될 때
  • 새로운 props가 들어올 때
  • shouldComponentUpdate에서 true가 반환될 때
  • foceUpdate가 실행될 때

 

최적화를 위한 방법

useCallback

컴포넌트가 렌더링 될 때 그 안에 있는 함수도 다시 만들게 된다.

똑같은 함수를 렌더링 될 때마다 계속 다시 만드는 것은 좋은 현상이 아니다.

특히나 자식 컴포넌트가 부모 컴포넌트의 함수를 똑같이 가지고 있다면, 같은 함수를 계속 다시 만들게 된다.

이 문제를 해결하기 위해 useCallback()으로 해결할 수 있다.

메모이제이션된 함수를 반환하는 함수

const textFunction = useCallback(() => {}, []);

의존성 배열(usecallback의 마지막 인수인 [])이 바뀌지 않는다면 메모이제이션된 함수를 사용한다.

 

useMemo 

사용 예시

function component({a,b}) {
const result = useMemo(() => compute(a,b), [a,b]);
return <div>{result}</div>
}
반응형