본문 바로가기

Front-End: Web/React.js

[코딩애플] 성능개선 2: 재렌더링 막는 memo, useMemo

반응형

memo

자식 컴포넌트의 재렌더링 막으려면 memo

버튼을 누르면 count가 +1씩 되는 버튼을 생성하자.

🕹️Cart.js

import { useState } from 'react';

function Child(){
    return <div>자식임</div>
}

function Cart(){
	const [count, setCount] = useState(0);
    
    return(
    	<div>
            <Child></Child>
            <button onClick={() => setCount(count+1)}>+</button>
        </div>)
}

이제 버튼을 누를 때마다 Cart 컴포넌트가 재렌더링이 된다. Cart 컴포넌트가 재렌더링되므로 <Child>와 같은 자식 컴포넌트들도 전부 재렌더링이 된다. 재런데링되는지 콘솔로 확인해보자.

function Child(){
    console.log('재렌더링됨')
    return <div>자식임</div>
}

버튼을 누를 때마다 콘솔이 찍힌다.

리액트는 원래 이런식으로 동작한다. 하지만 이런 것들이 나중에는 성능저하가 된다. 만약 <Child>가 렌더링 시간이 오래 걸리는 친구라면 button을 누를 때마다 <Child>라는 무거운 친구도 재렌더링되니까 시간이 오래걸릴 수 있다.

그래서 <Child> 컴포넌트를 꼭 필요할 때만 재렌더링되도록 해야 한다. 이때 쓰는게 memo다.

함수형 컴포넌트로 컴포넌트를 생성해주고, 함수를 memo로 감싼다.

import { useState, memo } from 'react';

const Child = memo(function(){
    console.log('재렌더링됨')
    return <div>자식임</div>
})

그러면 <Child>는 꼭 필요할 때만 재렌더링되기 때문에 버튼을 눌러도 콘솔이 찍히지 않는다.

⭐memo로 재렌더링 오래 걸리는 컴포넌트를 감싸놓으면 좋다.

memo 동작 원리: props가 변할 때만 재렌더링해줌

memo는 그냥 재렌더링을 막아주는게 아니라, **props가 변할 때만 재렌더링을 해준다**. <Child>에 props인 count를 줘서 확인해보자.

import { useState, memo } from 'react';

const Child = memo(function(){
    console.log('재렌더링됨')
    return <div>자식임</div>
})

function Cart(){
	const [count, setCount] = useState(0);
    
    return(
    	<div>
            <Child count={count}></Child>
            <button onClick={() => setCount(count+1)}>+</button>
        </div>)
}

그러면 버튼을 누를 때마다 <Child>에 props값이 변하므로 <Child>도 재렌더링된다.

props가 길고 복잡하면 손해일 수도

이걸 통해서 memo를 다 감싸면 안좋다는 걸 알게된다. 왜냐하면 memo로 감싼 컴포넌트는 재렌더링하기 전에

기존props === 신규props

를 계속 비교하고, 재렌더링 여부를 결정한다.

그래서 만약 <Child>로 전송되는 props가 길고 복잡하다면 기존 props와 신규 props를 비교하는데도 오랜 시간이 걸리기 때문에 손해다.

그러니까 온갖 컴포넌트에 다 memo를 갖다 붙이지 말고, 진짜 꼭 필요한 무거운 컴포넌트에만 붙이자. 근데 대부분에는 붙일 필요가 없는데 그냥 참고로만 알아두자.

useMemo

컴포넌트 렌더링시 1회만 실행해줌

무거운 연산을 하는 함수가 하나 있다고 하자.

function 함수(){
    return 반복문10억번 돌린 결과
}

function Cart(){
    const result = 함수();
}

Cart에 그냥 result = 함수()로 써놓으면 단점이 있다. Cart가 재렌더링될 때마다 이 함수가 계속 실행되기 때문에 매우 비효율적이기 때문이다.

개선을 하고 싶다면 useMemo를 이용해서 작성하자. 작성하는 방법은 useEffect와 매우 유사하다.

import { useMemo } from 'react';

function 함수(){
    return 반복문10억번 돌린 결과
}

function Cart(){
    const result = useMemo(() => 함수())
}

함수를 return해주는데, 그러면 Cart 컴포넌트가 처음 렌더링될 때에만 실행이 되고, 그 이후로는 영영 실행이 되지 않는다.

useEffect처럼 얘도 dependency를 집어 넣을 수 있다.

function Cart(){
    const result = useMemo(() => 함수(), [state])
}

그럼 state가 변경될 때에만 함수()가 실행돼서 result에 넣어진다.

그래서 꼭 필요할 때에만 함수를 실행시키고 싶으면 useMemo나 useEffect를 갖다 쓰면 된다.

useMemo vs useEffect

실행 시점에 차이가 있다.

useEffect는 html 보여주는 실행이 모두 끝나면 실행이 되고,

useMemo는 렌더링 될 때 같이 실행이 된다.

반응형