[React]Memoization 알아보기(Profiler, useCallback, usememo) (1)

rondido·2022년 11월 17일
0

React

목록 보기
14/40
post-thumbnail

메모제이션은 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술

전체는 Memo Component
item을 감싸는 comments
각 아이템들을 commentItem으로 Component로 만들어 간단한 예제를 살펴보자.

우선 Memo.jsx 파일 생성

import React, { useState } from 'react'
import Comments from './Comments';

const commentList =[
    {title:"commnet1", content:"message1", likes:1},
    {title:"commnet2", content:"message2", likes:2},
    {title:"commnet3", content:"message3", likes:3},
]

export default function Memo() {
    const [comments, setComments] = useState(commentList);
  return (
    <Comments commentList={comments}/>
  )
}

usestate를 통해 commnetList를 comments에 담아 줌.

Memo.jsx 파일 생성 후 App.js로 Memo.component 추가 하기

App.js


import "./App.css";

import Memo from "./components/3-8.Memoization/Memo";
function App() {
  return (
    <div className="App">

      <Memo />
    </div>
  );
}

export default App;

Comments.jsx 파일 생성

import React from 'react'
import CommentItem from './CommentItem'

export default function Comments({commentList}) {

  return (
    <div>
        {commentList.map(comment => <CommentItem
        key={comment.title}
        title={comment.title}
        content={comment.content}
        likes={comment.likes}
        />)}
    </div>
  )
}

Comments는 CommentItem을 계속 그린다.
commentItem의 key값은 유일성을 기반으로 작성되어야 한다.

CommentItem.jsx 파일 생성

import React from 'react'
import './CommentItem.css'

export default function CommentItem({title,content,likes}) {
  return (
    <div className='CommentItem'>
        <span>{title}</span>
        <span>{content}</span>
        <span>{likes}</span>
    </div>
  )
}

CommentItem.css 파일 생성

.CommentItem{
    border-bottom: 1px solid grey;
    padding: 10px;
    cursor: pointer;
}

위 코드를 통해 아래와 같은 결과가 도출


React.Memo

동일한 props로 렌더링을 한다면, React.memo를 사용하여 성능 향상을 누릴 수 있다.

memo를 사용하면 React는 컴포넌트를 렌더링하지 않고 마지막으로 렌더링 된 결과를 재사용함.

Memo.jsx를 아래 코드로 수정
memo를 넣고 HOC 개념을 통해 Memoization을 구현

import React, { memo } from 'react'
import './CommentItem.css'

 function CommentItem({title,content,likes}) {
  return (
    <div className='CommentItem'>
        <span>{title}</span>
        <br/>
        <span>{content}</span>
        <br/>
        <span>{likes}</span>
        <br/>
    </div>
  )
}

export default memo(CommentItem)

그렇다면 여기서 Memoizaition을 구현했는데 어떻게 최적화가 되었는지 확인 할 수 있는가?

props를 바꾸어 억지로 렌더링 되는 상황을 만들어보자

1초에 하나씩 새로운 컴포넌트가 새롭게 만들어지는 상황 만들기

Memo.jsx

import React, { useEffect, useState } from 'react'
import Comments from './Comments';

const commentList =[
    {title:"commnet1", content:"message1", likes:1},
    {title:"commnet2", content:"message2", likes:2},
    {title:"commnet3", content:"message3", likes:3},
]

export default function Memo() {
    const [comments, setComments] = useState(commentList);

    useEffect(()=>{
        const timer = setInterval(()=>{
            setComments((prevComments) => [
                ...prevComments,
                {
                    title:`commnet${prevComments.length +1}`, content:`message${prevComments.length + 1}`, likes:1
                },
            ]);
        },1000);
        
        //클린업
        return () =>{
            clearInterval(timer);
        }
    },[]);

  return (
    <Commnets commentList={comments}/>
  )
}

1초씩 새로운 컴포넌트가 생기는 것을 확인할 수 있다.

과연 이것은 지금 최적화가 되어 있는가?

최적화를 확인하기 위해 React에서 제공해주는 Profiler를 이용해보자


Profiler는 React 애플리케이션이 렌더링하는 빈도와 렌더링 비용을 측정
목적은 메모이제이션 같은 성능 최적화 방법을 활용할 수 있는 애플리케이션의 느린 부분들을 식별

Profiler 구현해보기

CommentItem.jsx

import React, { Profiler,memo } from 'react'
import './CommentItem.css'

 function CommentItem({title,content,likes}) {
    function onRenderCallback(
        id, // 방금 커밋된 Profiler 트리의 "id"
        phase, // "mount" (트리가 방금 마운트가 된 경우) 혹은 "update"(트리가 리렌더링된 경우)
        actualDuration, // 커밋된 업데이트를 렌더링하는데 걸린 시간
        baseDuration, // 메모이제이션 없이 하위 트리 전체를 렌더링하는데 걸리는 예상시간 
        startTime, // React가 언제 해당 업데이트를 렌더링하기 시작했는지
        commitTime, // React가 해당 업데이트를 언제 커밋했는지
        interactions // 이 업데이트에 해당하는 상호작용들의 집합
      ) {
        // 렌더링 타이밍을 집합하거나 로그...
        console.log(`actualDuration(${title}: ${actualDuration})`)
      }
  return (
    <Profiler id="CommentItem" onRender={onRenderCallback}>
    <div className='CommentItem'>
        <span>{title}</span>
        <br/>
        <span>{content}</span>
        <br/>
        <span>{likes}</span>
        <br/>
    </div>
    </Profiler>
  )
}

export default memo(CommentItem)

자세한 내용은 https://ko.reactjs.org/docs/profiler.html 참조


Github 코드

위 내용은 React 강의 영상을 정리한 내용 입니다.

profile
함께 성장하는 것을 좋아하는 프론트엔드 개발자

0개의 댓글