뚜벅

리액트 컴포넌트 최적화 본문

React

리액트 컴포넌트 최적화

초코맛젤리 2023. 2. 12. 02:00

리액트 리렌더링

1. props, state 변경 시 리렌더링

2. 부모컴포넌트 리렌더링시 자식 컴포넌트 리렌더링

 

리액트에서는 위의 조건일때 리렌더링이 발생하는데 이것을 최적화하는 방법을 정리합니다.

React.memo 

React.memo 는 고차 컴포넌트 (HOC) 로 함수 & 클래스 컴포넌트에서 사용가능합니다.

 

React.memo을 통해 최적화를 할 경우 렌더링에 될 때 props를 체크하여 이전

props에서 변화가 있다면 렌더링을 하고 변화가 없다면 기존에 렌더링된 결과를 재사용합니다.

React.memo는 오직 props의 변화에만 의존하는 최적화 방법!

그렇기 때문에 useState, useReducer, useContext를 통해 state가 변경되면 리렌더링이 발생합니다.

 

funtion App() {
    const [parentAge, setParentAge] = useState(0);
    const [childAge, setChildAge] = useState(0);
    
    const incrementParentAge = () => {
        setParentAge(pre => pre+1)
    }
    
    const incrementChildAge = () => {
        setChildAge(pre => pre+1)
    }
    
    return (
        <div>
            <p>age: {parentAge}</p>
            <button onClick={incrementParentAge}>부모 나이 증가</button>
            <button onClick={incrementChildAge}>자식 나이 증가</button>
            <Child name={'초코맛젤리'} age={childAge}/>
        </div>
    )
}
import React from 'react'

function Child ({name, age}) {
    return(
        <div>
            <p>이름 : {name}</p>
            <p>나이 : {age}</p>
        </div>
    )
}

export default Child

 

위의 코드는 parentAge를 증가하는 버튼을 눌렀을 때, Child 컴포넌트도 불필요하게 리렌더링이 되고

만약 Child 컴포넌트 내부에 복잡한 로직이 있을경우 성능의 저하를 일으킵니다.

그렇기 때문에 이 부분은 React.memo를 사용해서 최적화할 수 있습니다. 

 

import React, {memo} from 'react'

function Child ({name, age}) {
    return(
        <div>
            <p>이름 : {name}</p>
            <p>나이 : {age}</p>
        </div>
    )
}

export default memo(Child)

 

그렇다면 React.memo를 통해서 모든 컴포넌트를 최적화하면 좋은것인가?

React.memo를 사용할 경우 렌더링 횟수를 줄여줄 수 있지만 무분별하게 사용하면 안 된다.

왜냐하면 렌더링 된 결과를 메모리에 저장하기 때문에 메모리를 추가적으로 사용하기 때문이다.

React.memo 사용하면 좋은 경우

1. 컴포넌트가 같은 props로 자주 렌더링 될 때

2. 컴포넌트가 렌더링 될 때마다 복잡한 로직을 처리해야 될 때

 

useMemo

훅이기 때문에 함수 컴포넌트에서만 사용가능합니다.

의존성 배열 안에 넣은 내용이 바뀌면 콜백함수를 연산해 주고 아니면 연산한 을 재사용합니다.

useMemo(()=> {...},[])

 

funtion App() {
    const [parentAge, setParentAge] = useState(0);
    
    const incrementParentAge = () => {
        setParentAge(pre => pre+1)
    }

    const name = {
        lastName: '초코맛'.
        firstName: '젤리',
    }

    return (
        <div>
            <p>age: {parentAge}</p>
            <button onClick={incrementParentAge}>부모 나이 증가</button>
            <Child name={name}/>
        </div>
    )
}
import React, {memp} from 'react'

function Child ({name}) {
    return(
        <div>
            <p>성 : {name.lastName}</p>
            <p>이름 : {name.firstName}</p>
        </div>
    )
}

export default memo(Child)

위의 코드는 Child 컴포넌트에서 name 변수가 props로 받고 있습니다.

그리고 Child 컴포넌트는 React.memo를 사용하여 최적화를 하고 있습니다.

 

그렇다면! 똑같이 parentAge를 증가하는 버튼을 눌렀을 때 Child 컴포넌트는 리렌더링이 발생하지 않는다고

생각하지만 버튼을 눌렀을 때는 리렌더링이 발생합니다!! 

 

그 이유는 부모 컴포넌트의 상태가 리렌더링 되면서 내부의 모든 변수들이 초기화되는데 

이때, name 변수 또한 초기화가 되면서 새로운 메모리 주소를 참조하기 때문에

props 체크를 했을 때 리렌더링이 발생합니다

(name은 객체이기 때문에 같아 보일지라도 다른 메모리주소를 참조한다)

const obj = {a : 1}
const obj2 = {a : 1}
console.log(obj === obj2) // false

 

이때 name에 아래와 같이 useMemo를 사용하면 리렌더링이 발생하지 않습니다.

import {useMemo} from 'react'

function App(){
    // ...
    const name = useMaemo(() => {
        return {
             lastName: '초코맛',
             firstName: '젤리'
         }
     },[])
    // ...
}

 

useCallback

훅이기 때문에 함수형 컴포넌트에서만 사용 가능합니다.

의존성 배열 안에 넣은 내용이 바뀌면 콜백함수를 연산해 주고 아니면 연산한 함수를 재사용합니다.

useCallback(()=>{...},[])
funtion App() {
    const [parentAge, setParentAge] = useState(0);
    
    const incrementParentAge = () => {
        setParentAge(pre => pre+1)
    }
    
    const tellMe = () => {
    	console.log("먹어라")
    }

    return (
        <div>
            <p>age: {parentAge}</p>
            <button onClick={incrementParentAge}>부모 나이 증가</button>
            <Child name={'초코맛젤리'} tellMe={tellMe}/>
        </div>
    )
}
import React from 'react'

function Child ({name,tellMe}) {
    return(
        <div>
            <p>이름 : {name}</p>
            <button onClick={tellMe}>밥 주세요</button>
        </div>
    )
}

export default memo(Child)

 

이것도 똑같습니다. 전달받는 tellMe 또한 객체이고 부모 컴포넌트에서 리렌더링이 발생할 때 새로 초기화되기 때문에

React.memo를 사용하더라도 리렌더링이 발생합니다.

 

이때는  tellMe 함수에 에 아래와 같이 useCallback를 사용하면 리렌더링이 발생하지 않습니다.

import {useCallback} from 'react'

function App(){
    // ...
    const tellMe = useCallback(() => {
        console.log('먹어라')
     },[])
    // ...
}

 

정리

React.memo : HOC으로 함수 & 클래스 컴포넌트 모두 사용가능

렌더링에 될 때 props를 체크하여 이전 props에서 변화가 있다면 렌더링을 하고 변화가 없다면

기존에 렌더링 된 결과를 재사용합니다

 

useMemo : Hook으로 함수 컴포넌트에서만 사용가능 하고 특정 결괏값을 재사용할 때 사용합니다.

의존성 배열 안에 넣은 내용이 바뀌면 함수를 호출해서 값을 연산해 주고, 만약에 내용이 바뀌지 않았다면 이전에 연산한 값을 재사용합니다.

 

useCallback : Hook으로 함수 컴포넌트에서만 사용가능하고 특정 함수를 새로 만들지 않고

재사용하고 싶을 때 사용합니다.

의존성 배열 안에 넣은 내용이 바뀌면 함수를 새로 생성, 만약에 내용이 바뀌지 않았다면 이전에 연산한 함수를 재사용합니다.

 

 

 

 

17. useMemo 를 사용하여 연산한 값 재사용하기 · GitBook

17. useMemo 를 사용하여 연산한 값 재사용하기 이번에는 성능 최적화를 위하여 연산된 값을 useMemo라는 Hook 을 사용하여 재사용하는 방법을 알아보도록 하겠습니다. App 컴포넌트에서 다음과 같이 co

react.vlpt.us

 

18. useCallback 를 사용하여 함수 재사용하기 · GitBook

18. useCallback 을 사용하여 함수 재사용하기 useCallback 은 우리가 지난 시간에 배웠던 useMemo 와 비슷한 Hook 입니다. useMemo 는 특정 결과값을 재사용 할 때 사용하는 반면, useCallback 은 특정 함수를 새

react.vlpt.us

 

'React' 카테고리의 다른 글

가상돔 - Virtual DOM  (0) 2023.02.11
Pomodoro - TS, React, Tailwind CSS  (0) 2023.01.02
외부 클릭 이벤트 - React  (0) 2022.10.05
react 에서 redux 사용해보기! (1)  (0) 2022.09.17
Netlify 배포 에러 해결 - React Router Dom  (0) 2022.09.02