렌더링 최적화를 진행하기 위해
Highlight updates when components render.
개발자 도구에서 해당 기능을 키고 input에 입력을 해봤는데
불필요하게 렌더링되는 부분들이 많았다.
React.memo
와 useCallback
을 사용하여 해당 부분들을 해결해주었다.
우선 렌더링 최적화할때 자주 나오는 개념인 메모이제이션에 대해 알아보자.
메모이제이션(memoization)은 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술
리액트에서의 메모이제이션은 특정 값을 저장해두었다가, 해당 값이 필요할 때 다시 계산하지 않고 저장해둔 값을 사용하는 기술이다.
React는 이전 렌더링 결과와 비교하여 DOM 업데이트를 결정하는데, 렌더링 결과가 이전과 다르면 React는 DOM을 업데이트한다.
React에서 리렌더링이 발생하는 시점은 state
가 변했을때다. 특정 컴포넌트의 state
가 변하면, 해당 컴포넌트와 해당 컴포넌트 하위에 있는 모든 컴포넌트들에서 리렌더링 이 발생한다. 이때 하위 컴포넌트의 props가 변하지 않으면 UI가 변하지 않았을 가능성이 높기에 리렌더링 여부를 결정하기 위해 React.memo
함수를 사용한다.
React.memo
함수는 컴포넌트 이전의 props와 다음 렌더링 props를 비교해서 차이가 있을때만 리렌더링을 수행한다.
React 공식문서
memo를 사용하면 컴포넌트의 props가 변경되지 않은 경우 리렌더링을 건너뛸 수 있습니다.
EventWritePage.js
├── EventTitleInput.js
├── EventInfoInput.js
├── EventExplainInput.js
해당 페이지[EventWritePage.js
]에서 제목, 상세정보, 설명을 적는 컴포넌트는 이미 분리를 해둔 상태여서 해당 컴포넌트들을 React.memo 처리를 했다. 제목을 적을때는 상세정보, 설명의 상태가 변하지 않고, 상세정보를 적을때는 제목, 설명의 상태가 변하지 않고, 설명을 적을때는 제목, 상세정보의 상태가 변하지 않기 때문에 React.memo를 사용했다.
💡 하위 컴포넌트로 넘겨주는 props가 변하지 않았기 때문!
import React from 'react';
const EventTitleInput = ({ ... }) => {
~~~~
}
export default React.memo(EventTitleInput);
useCallback은 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용한다.
React 공식문서
리렌더링 사이에 함수 정의를 캐시할 수 있게 해주는 React 훅입니다.
input에서 사용하는 onChange 이벤트에 사용하는 함수는 text 상태만을 참조하기 때문에 함수를 한번만 생성하고 해당 함수를 재사용해도 된다. 의존성 배열이 비어있으므로 아래와 같이 사용해주었다.
const handleChangeInput = useCallback((e) => {
setExplain(e.target.value);
}, []);
<input type="text" value={explain} onChange={handleChangeInput} />
<최적화 전> 4.1ms 소요
<최적화 후> 0.4ms 소요
memo를 사용하여 최적화를 하게 된 결과 제목 이외의 부분은 렌더링 되지 않아서 회색처리 되었고 0.4ms 소요되었다. 렌더링 소요시간을 10분의 1로 줄였다.
<최적화 전> 6.3ms 소요
<최적화 후> 2.5ms 소요
<최적화 전> 2ms 소요
<최적화 후> 0.5ms 소요
최적화 전, 게시물 작성 렌더링 총 소요 시간 12.4ms
최적화 후, 게시물 작성 렌더링 총 소요 시간 3.1ms
렌더링 소요 시간을 4분의 1로 줄였다.
ps.
리액트 공식문서에서는 < 모든 곳에 memo, useCallback을 추가해야할까요? > 하고 메모이제이션을 꼭 사용하지 않아도 되는 상황들에 대해 추가적으로 설명을 하고 있어서 최적화할 때 해당 부분에 해당되지 않는지 꼭 확인해보자.