메모제이션은 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술
전체는 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;
}
위 코드를 통해 아래와 같은 결과가 도출
동일한 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 애플리케이션이 렌더링하는 빈도와 렌더링 비용을 측정
목적은 메모이제이션 같은 성능 최적화 방법을 활용할 수 있는 애플리케이션의 느린 부분들을 식별
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 참조
위 내용은 React 강의 영상을 정리한 내용 입니다.