리액트 성능 최적화의 필요성
리액트에서 컴포넌트는 state, props, context가 바뀔 때,
그리고 부모 컴포넌트가 재실행될 때 재실행되고 재평가된다.
컴포넌트가 재실행된다고 해서 반드시 실제 DOM이 변경되는 것은 아니다.
virtual DOM상에서 변경 사항을 감지할 때만 실제 DOM에 변경 사항이 반영된다.
그렇지만 변경할 필요가 없는 컴포넌트의 재실행 및 재평가는 리액트의 성능에 영향을 줄 수 있다.
특히 애플리케이션의 상위에 존재하는 컴포넌트가 재실행·재평가된다면
그 하위의 모든 컴포넌트도 재실행될 것이기 때문에
애플리케이션의 규모가 클 경우에는 이것이 성능에 안 좋은 영향을 줄 수 있다.
그래서 리액트에서는 성능 최적화를 위해 React.memo와 useCallback을 사용할 수 있다.
useMemo는 prop이 바뀐 경우에만 컴포넌트를 재실행할 수 있게 만들어 주고,
useCallback은 함수를 저장해 두고 컴포넌트 재실행 시마다 함수가 재생성되지 않아도 되게 해준다.
메모이제이션을 위한 훅 useMemo는 연산의 결과를 저장해둬서
복잡한 연산을 반복적으로 하지 않아도 되게 함으로써 성능 개선에 도움을 준다.
React.memo
컴포넌트의 불필요한 재실행 방지를 위해 먼저 React.memo를 쓸 수 있다.
해당 컴포넌트를 React.memo로 랩해주기만 하면 props가 바뀌지 않는 한 컴포넌트는 재실행되지 않고
그 후손 컴포넌트들도 마찬가지로 불필요한 재실행이 발생하지 않는다.
그럼 모든 컴포넌트에 React.memo를 쓰면 좋을까? 그렇지 않다.
최적화에는 비용이 따른다. 재실행 여부를 판단하기 위해 기존 props와 새로운 props를 비교해야 하므로 컴포넌트를 재실행하는 데 드는 비용과 props를 저장하고 비교하는 비용을 비교해 React.memo를 쓸 가치가 있는지 판단해야 한다.
컴포넌트의 복잡성이 클수록, 컴포넌트가 트리의 상위에 있을수록 그럴 만한 가치가 있을 가능성이 높다.
useCallback
useCallback은 함수를 저장해두고 컴포넌트 재실행시마다 함수가 재생성되는 것을 막아 준다.
함수 재생성을 막기 위한 훅이 따로 필요한 이유는 자바스크립트에서 함수가 참조형이기 때문이다.
똑같은 기능과 내용의 함수라고 해도 주소값이 다르면 다른 함수로 인식되므로 비교를 위해서는 별도의 방법을 적용해야 한다.
const cachedFn = useCallback(fn, dependencies)
fn은 캐시할 함수 값이다. 첫 렌더 때 useCallback이 이 함수를 반환해 cachedFn에 저장된다.
종속성이 변경되지 않은 경우 다음 렌더링 때 함수가 재생성되지 않게 된다.
종속성이 변경되면 다시 함수를 저장하는 과정을 반복한다.
만약 prop에 전달된 값이 함수라면 React.memo로는 불필요한 재실행을 막지 못한다.
이런 컴포넌트를 최적화하기 위해서는 useCallback을 사용하자
useMemo
useMemo는 복잡한 연산을 반복하지 않아도 되게 해 주는 메모이제이션 훅이다.
const cachedValue = useMemo(calculateValue, dependencies)
calculateValue는 저장할 값을 계산하는 함수다. 첫 렌더링을 할 때 이 함수가 호출되고, 종속성이 변경되지 않는다면 다음 렌더링 때 동일한 값이 반환된다. 만약 종속성이 변경됐다면 이 함수를 다시 호출하고 결과를 다시 저장한다.
dependencies는 종속성으로, 종속성 배열 안의 요소의 값이 업데이트 될 경우에만 저장해 둔 값을 업데이트하고 다시 저장한다. useEffect의 종속성 배열과 마찬가지로 빈 배열일 경우 최초 렌더링 시 한번만, 생략 시 모든 렌더링시 calculateValue가 호출된다.
컴포넌트 내에 복잡한 연산이 있는 경우에 useMemo를 사용하면 컴포넌트가 재실행되더라도 반복적으로 동일한 연산을 하지 않아도 되게 만들 수 있다.
'React' 카테고리의 다른 글
[React] 리액트 라우터 data api 사용하기 (0) | 2023.04.26 |
---|---|
[Redux] 비동기 작업 처리하기(useEffect, thunk) (0) | 2023.04.21 |
[Redux] 리덕스 툴킷 사용하기 (2) | 2023.04.14 |
[Redux] 리덕스 기초 (1) | 2023.04.13 |
[React] useRef (0) | 2023.04.12 |