쓸데 없는 재렌더링 막는 memo

Steve·2021년 6월 17일
0

컴포넌트는 컴포넌트와 관련된 state 또는 props가 변경되면 항상 자동 재렌더링 됩니다.
하지만 가만히 있어도 되는 컴포넌트 마저 재렌더링 된다면 불필요한 메모리누수가 생기겠죠?
이런 예시가 있습니다.
부모 컴포넌트의 props내용이 일부 변경되면 props를 전송받고 있는 자식 컴포넌트들도 전부 재렌더링 됩니다. 불필요한 움직임이 많아지면 사이트 구동 속도가 저하 될겁니다. 이걸 해결하고자 탄생한것이

memo()

function Cart(){
  return (
    <Parent /> //이렇게 놓면 미리보기 까지 가능하다
  )
}

function Parent(props){
  return (
    <div>
      <Child1/>
      <Child2/> 
    </div>
  )
}
function Child1(){
  useEffect( ()=>{ console.log('렌더링됨1') } ); // 컴포넌트가 로드/ 재렌더링되면 useEffect 실행('react'로부터 import)
  return <div>1111</div>
}
function Child2(){
  useEffect( ()=>{ console.log('렌더링됨2') } );
  return <div>2222</div>
}

여기서 갑자기 props를 전달하고 하고 싶으면?

Cart안에 있던 존박, 20이라는 데이터를 Child1/Child2까지 props를 각각 전달하려면?

function Cart(){
  return (
    <Parent 이름="존박" 나이="20"/> // 단순 값 전달이면 중괄호 안붙여도 됨
  )
}

function Parent(props){
  return (
    <div>
      <Child1 이름={props.이름}/>
      <Child2 나이={props.나이}/> 
    </div>
  )
}
function Child1(){
  useEffect( ()=>{ console.log('렌더링됨1') } ); // 컴포넌트가 로드/ 재렌더링되면 useEffect 실행('react'로부터 import)
  return <div>1111</div>
}
function Child2(){
  useEffect( ()=>{ console.log('렌더링됨2') } );
  return <div>2222</div>
}

여기서 <Parent 이름="존박">의 값을 바꿔버린다면?

▲처럼 존박을 존박1로 변경해보자.
Child1과 Child2까지 모두 재렌더링 되는데 당연히 메모리를 쓸데없이 잡아먹게된다. 이걸 방지하기위해서 memo()로 재렌더링 될필요 없는 곳을 둘러싸준다.

▲ 개발자 도구에서 Parent를 클릭하면 props를 수정해볼수 있고 존박1로 변경했더니
Child1,2 모두 재렌더링됨을 확인할 수 있다.(이름="존박"이라는 props만 변경했으니 Child2는 상관이 없으니 재렌더링 될필요가 없는데!!)

리액트 앱은 원래 그런식으로 동작합니다.
Parent를 구성하는 state나 props가 변경되면 그것과 관련된 모든 컴포넌트를 다 재렌더링 시킨다.
가만히 얌전히있는 컴포넌트의 재렌더링을 막고싶으면 memo() 함수를 이용하면 됩니다.

memo()로 컴포넌트 불필요한 재렌더링 막기

memo()는 “props 변경이 안된 컴포넌트는재렌더링 하지말아주세요~”
라고 쓰고싶을 때 사용합니다.
써보려면 ‘react’ 라이브러리로부터 import 해오시면 됩니다.

import React, {useEffect, memo} from 'react';

function Cart(){
  return (
    <Parent 이름="존박" 나이="20"/>
  )
}

function Parent(props){
  return (
    <div>
      <Child1 이름={props.존박}/>
      <Child2 나이={props.나이}/>
    </div>
  )
}
function Child1(){
  useEffect( ()=>{ console.log('렌더링됨1') } );
  return <div>1111</div>
}
let Child2 = memo(function(){
  useEffect( ()=>{ console.log('렌더링됨2') } );
  return <div>2222</div>
})

▲ 1. 상단에서 memo를 import 해왔고
2. Child2라는 원하는 컴포넌트를 memo로 감쌌습니다.

이렇듯 그냥 memo라는걸로 감싸시면 아까처럼
“이 컴포넌트는 얘랑 관련있는 props가 변경이 될때만 제렌더링해주세요~”
라고 사용이 가능합니다. 쉽습니다. 끝!
Child2함수 만드는데 갑자기 웬 let??

자바스크립트는 함수만들 때 두가지 방법이 있습니다.

function 함수(){}
let 함수 = function(){ }

둘 중 밑의 방법을 이용했을 뿐입니다.
밑으로 만드셔야 memo로 감쌀 수 있습니다

그럼 아까처럼 똑같이 이름을 존박1로 변경해보면
이제는 Child2 라는 존박과 관련없는 컴포넌트는 렌더링되지 않습니다.
아무튼 이게 컴포넌트가 너무 크거나 해서 잦은 재렌더링이 부담스러울 때 쓰는 방법입니다.

그래서 memo이걸 막 갖다 써도 되냐?

props가 매우 방대하고 큰경우엔 오히려 손해일 수 있다.
memo로 감싼 컴포넌트는 헛되게 재렌더링 안시키려고 기존 props와 바뀐 props를 비교하는 연산이 추가로 진행되는데 props가 크고 복잡하면 이거 자체로도 부담이 된다.
쓸지 말지 평가하려면 리액트 개발자도구에서 렌더링 속도를 측정해볼 순 있으나
그것 조차도 귀찮으니까 그냥 쪼그만 싸이트 만들때나 컴포넌트 내부에 HTML양이 적을경우엔 memo는 가급적 쓰지말자

profile
Front-Dev

0개의 댓글