useMemo로 성능 개선하기

Kaia·2022년 8월 4일
0

react hooks 중 useMemo를 사용해서 불필요한 렌더링을 방지하고자 했다. 불필요한 렌더링을 방지함과 동시에 성능저하를 일으키는 로직과 렌더링 시간 등을 확인하고자 개발도구를 처음으로 사용해보았다.

useMemo?

의존 배열의 값이 변경되지 않으면 메모된 값을 반환한다.
의존된 배열의 값이 변경되었을 때만 메모이제이션된 값만 다시 계산한다.
함수형 컴포넌트는 렌더링 -> 함수호출 -> 변수초기화
즉, 렌더링될 때 마다 모든 변수 초기화된다.

useMemo를 사용하게되면,
렌더링 -> 함수호출 -> memoization 재활용 (굿)

값을 재활용하기 위해 메모리에 저장해놓기 때문에 남용 시 성능이 안좋아질 수 있으니, 필요할 때만 사용 !!

리렌더링 원인

  • '컴포넌트의 렌더링'은 함수(컴포넌트)를 호출했기에 실행
  • 함수(컴포넌트)가 실행되면 내부의 로직들 또한 매번 다시 선언
  • 컴포넌트는 자신의 state가 변하거나 부모에게서 받는 props에 변동이 일어나면 렌더링
  • 부모컴포넌트가 리렌더링되면 바뀌는 내용이 없더라도 자식 컴포넌트 또한 리렌더링

useMemo는 값을 저장하여 의존배열의 값이 바뀔때만 재렌더링하고 그 외에는 저장된 값을 반환한다.
즉, 불필요한 리렌더링을 줄여서 비용을 줄이기 위해 사용한다.


useMemo를 사용하므로써 성능이 향상되었는지, 불필요한 렌더링은 일어나지 않는지, 또 성능 개선이 필요한 부분이 있는지 확인하기 위해 react-devtools를 설치했다.


devtools?

여기서 설치
https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi

렌더링 속도, 횟수, 변수 체크 등을 할 수 있어서 유용하다.

  • components : 프로젝트 구조 보기 쉬움
  • profiler : 성능 측정에 용이 (렌더링 속도 및 디테일한 정보)

issue(라 쓰고 구구절절이라 읽는다)
categoryItem 클릭 시 상태값이 바뀌는데 이 상태는 부모 컴포넌트에서 생성하므로, 부모컴포넌트가 리렌더링되면서 그 하위의 모든 자식 컴포넌트 리렌더링된다.그러나 같은 페이지에 배치된 expand(더보기버튼)의 경우는 직접 사용되는 컴포넌트 내에 state를 정의하고 변경하기 때문에 버튼을 클릭하더라도 해당 컴포넌트와 자식 컴포넌트들만 리렌더링 된다. categoryItem의 경우는 최상단의 부모컴포넌트(main.tsx)에서 state를 관리(데이터받아오고 변경하고)하고, props로 상태와 이벤트 모두 내려주기 때문에 하위의 자식 컴포넌트들이 모두 리렌더링된다.렌더링을 방지하기위해 하위 컴포넌트들에 useMemo를 거는 방법도 있으나, main.tsx가 리렌더링되면 해당 컴포넌트 내에 선언된 함수들도 모두 새로 생성되기 때문에 다른 자식 컴포넌트에 props로 변수와 함수를 넘겨주고있는 현재와 같은 구조에는 해당 props를 자식 컴포넌트에서 쓰든 안쓰든 모두 리렌더링 된다.이를 해결하기 위해서 useCallback으로 함수를 생성하거나 comp를 사용하는 방법이 있다. 또는 해당 자식 컴포넌트에서 setState를 실행시키는것, 변경될 상태값을 해당 자식 컴포넌트로 옮기고 서버요청을 실행하는 방법이 있을 것 같다. 그렇지만 데이터는 한 곳에서 처리한다는 구조에 맞지는 않는다. (해결중입니다)

** compFunc에는 비교함수를 작성한다. 결과값이 true면 리렌더링하고, false면 이전 렌더링 결과를 그대로 출력한다 (https://coding0.tistory.com/56)

//Child.js

import React, { memo } from "react"

const getCube = useCallback((n) => n+1, [])


const Child = ({ id, count, getCube }) => {
  console.log(id + " 리렌더링...")
  return (
    <div>
      [ 카운터 {id} ] : {getCube(count)}
    </div>
  )
}

const comp = (prev, next) => {
  return prev.count === next.count
}

export default memo(Child, comp)

0개의 댓글