본문 바로가기

Develop Log/React

React-Memoization

반응형

React rendering

  • React는 컴포넌트를 렌더링 한 뒤 이전 렌더된 결과와 비교하여 DOM을 업데이트 함
  • 함수형 컴포넌트 기준 React.useState()setter, React.useReducer()dipatches가 실행되면 해당 컴포넌트가 업데이트 된다
  • React의 컴포넌트가 업데이트 되면 업데이트 되는 컴포넌트 내부에 있는 모든 자식 컴포넌트를 순차적으로 리렌더링 한다.
  • Parent > Child > GrandChild 의 순으로 컴포넌트가 구성 되어 있을 경우
    Child 컴포넌트가 업데이트 된다면 상위 컴포넌트인 Parent 컴포넌트는 리렌더링 하지 않지만 하위 컴포넌트인 GrandChild컴포넌트는 다시 렌더링 된다
  • 만약 GrandChild 컴포넌트 내부에 자식 컴포넌트가 존재한다면 해당 컴포넌트도 똑같이 리렌더링 된다(업데이트되는 컴포넌트의 하위 모든 컴포넌트가 리렌더링)

Memoization

  • 기존에 수행한 연산 결과를 저장하여 이후 동일한 연산,입력이 들어오면 저장된 결과를 보내주여 재활용하는 프로그래밍 기법
  • 중복 연산을 피할 수 있어 성능 최적화에 도움이 된다
  • 바로 이전의 값만 메모이제이션하기 때문에 업데이트 되는 값이 2번째, 3번째 전 값과 같다고 하더라도 바로 이전 값과 다르다면 리렌더링 된다
  • React에서 메모이제이션을 위한 hook으로 React.memo, React.useCallback, React.useMemo가 있다

React.useMemo

  • 메모제이션된 값을 반환할 때 사용
  • React.useCallback은 함수 자체를 메모이제이션 하지만 React.useMemo의 경우 반환되는 값을 메모이제이션 하여 재사용하는 차이점이 있음
    const memo = React.useMemo(()=> {
        ...
    },[val])
  • React.useMemo의 두번째 인자에서는 React.useCallback과 달리 값을 재활용여부를 결정하는 값을 넣어야한다
  • 두번째 인자의 값이 변경될 때만 내부에 있는 코드가 실행이 된다

React.useCallback

  • 특정 함수를 새로 만들지 않고 재사용하기 위해 사용
  • 적용하고자 하는 함수에 감싸주어 사용
    const handleEvent = React.useCallback(()=> {
        ...
    },[state, props, ...])
  • 함수 내부에서 사용하는 state 또는 props가 있다면 두번째 배열 인자에 반드시 넣어주어야 함
  • 배열 안에 값을 넣지 않는다면 함수 내부에서 해당 값들을 참조할 때 가장 퇴신 값을 참조한다는것을 보장할 수 없음
  • props로 함수를 받아왔다면 함수를 넣어주어야 함

React.memo

  • 부모컴포넌트의 업데이트로 인해 자식 컴포넌트의 Props가 변경이 되지 않는 경우에도 리렌더링이 된다면 React.memo()를 사용하여 불필요한 업데이트를 줄여 성능상에 이점을 가질 수 있다
  • 컴포넌트를 React.memo()로 감싸주면 컴포넌트가 업데이트 됐을 때의 렌더링 결과를 메모이징하고 리렌더링이 발생됐을 때 메모이징된 결과와 비교후 변경사항이 없다면 메모이징된 내용을 재사용 한다
  • 같은 props로 자주 렌더링이 발생되는 컴포넌트에 사용하기 적합
  • props로 함수를 넘겨 줄 경우 React.useCallback()을 이용하여 동일한 콜백 인스턴스로 설정해주어야 React.memo()가 정상적으로 동작한다
  • 함수는 일반 객체와 동일한 비교원칙을 따라 오직 자신에게만 동일하기 때문
  • React.memo는 props를 비교할 때 얕은 비교를 한다
  • props비교 방식을 수정하고 싶다면 두번째 매개변수로 비교함수를 넣어주면 된다
    React.memo(Component, [비교방식 Function])
  • 깊은 비교를 위해 사용하는 라이브러리 fast-deep-equal을 이용한 방식
    import isEqual from 'fast-deep-equal'
    import React from 'react'

    interface ComponentProps {
        ...    
    }

    const Component:React.FC<ComponentProps> = (props) => {
      ...
    }

     export default React.memo(Component, isEqual)

참고

https://ko.reactjs.org/docs/hooks-intro.html
https://ui.toast.com/weekly-pick/ko_20190731
https://ko.wikipedia.org/wiki/%EB%A9%94%EB%AA%A8%EC%9D%B4%EC%A0%9C%EC%9D%B4%EC%85%98
https://black7375.tistory.com/79
https://react.vlpt.us/basic/18-useCallback.html

반응형