Programming/React.js, Next.js

[React Conf 2024] 이제 useMemo, useCallback 필요 없음. 리액트 컴파일러란??

Juun 2024. 5. 31. 20:37
반응형

이번 2024년 5월 15일부터 16일까지 개최한 행사인 React Conf 2024에서 발표된 내용을 기반으로 작성되었습니다.

 

리액트 컴파일러란?

리액트 19에 도입될 리액트 컴파일러는 공식 문서의 일부분에는 이렇게 설명되어 있습니다.

React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as useMemo, useCallback, and React.memo. With these APIs you can tell React that certain parts of your application don’t need to recompute if their inputs haven’t changed, reducing work on updates. While powerful, it’s easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don’t have any meaningful changes.

 

애플리케이션을 최적화하기 위해 React Compiler는 자동으로 코드를 메모합니다. useMemo, useCallback, 등의 API를 통한 메모이제이션은 오늘날 익숙하실 것입니다 React.memo. 이러한 API를 사용하면 입력이 변경되지 않은 경우 애플리케이션의 특정 부분을 다시 계산할 필요가 없음을 React에 알릴 수 있으므로 업데이트 작업이 줄어듭니다. 강력하지만 메모를 적용하는 것을 잊어버리거나 잘못 적용하기 쉽습니다. 이는 React가 의미 있는 변경 사항이 없는 UI 부분을 확인해야 하기 때문에 비효율적인 업데이트로 이어질 수 있습니다.

 

 

리액트 컴파일러가 없었을땐??

리액트에서 값을 메모이제이션을 할때 보통 useMemo나 useCallback을 사용하고 있습니다.

// useMemo
const computedValue = useMemo(() => expensiveComputation(count), [count]);

 

useMemo는 계산 비용이 큰 값을 메모이제이션하여 성능을 최적화하는 데 사용됩니다. 의존성 배열이 변경되지 않는 한, 메모이제이션된 값을 반환합니다.

 

// useCallback
const handleClick = useCallback(() => {
    console.log('Button clicked');
    setCount(count + 1);
  }, [count]);

useCallback은 콜백 함수의 메모이제이션을 위해 사용됩니다. 의존성 배열이 변경되지 않는 한, 동일한 함수 인스턴스를 반환합니다.

 

이 두 예시는 각각 useMemouseCallback을 사용하여 성능을 최적화하는 방법을 보여줍니다. useMemo는 계산 비용이 큰 값을 메모이제이션하고, useCallback은 함수의 인스턴스를 메모이제이션하여 불필요한 렌더링을 방지합니다.

 

이전에는 이러한 방법으로 성능 최적화를 하곤 했습니다.

 

그러나 의존성 관리를 잘못 관리하면 아래와 같은 문제가 생기곤 했습니다.

 

1. 불필요한 재계산 및 재생성:

의존성 배열에 필요 이상의 변수를 포함하면, 의존성이 변경될 때마다 불필요하게 함수나 값이 재계산됩니다. 이는 오히려 성능을 저하시킬 수 있습니다.
예를 들어, useMemo나 useCallback의 의존성 배열에 변화가 자주 발생하는 값을 포함하면, 해당 훅이 너무 자주 재평가되어 성능 이점이 사라집니다.

2. 의도하지 않은 메모이제이션 실패:

의존성 배열에 필요한 변수를 포함하지 않으면, 의존성이 변경되어도 값이나 함수가 업데이트되지 않습니다. 이는 의도한 동작을 방해하고, 최신 상태를 반영하지 못하게 됩니다.
예를 들어, 의존성 배열에서 상태 값이나 props를 누락하면, 해당 상태나 props가 변경되어도 훅이 다시 계산되지 않아 버그가 발생할 수 있습니다.

 

리액트 컴파일러는 어떻게 성능최적화를 할까?

리액트 컴파일러의 깃헙을 살펴보면 세 가지 기능에 중점을 둘 예정입니다.

 

1. 컴포넌트의 계단식 재렌더링 방지 (성능 최적화)

부모 컴포넌트의 재렌더링이 자식 컴포넌트 트리의 여러 컴포넌트를 재렌더링하게 만드는 경우, 메모이제이션을 통해 부모 컴포넌트만 변경되었을 때 자식 컴포넌트들의 불필요한 재렌더링을 방지할 수 있습니다.

 

2. React 외부의 비용이 큰 계산을 건너뛰기 (성능 최적화)
컴포넌트나 훅 내에서 expensivelyProcessAReallyLargeArrayOfObjects()와 같은 비용이 큰 함수를 호출하는 경우, 메모이제이션을 통해 이러한 계산을 건너뛰고 성능을 최적화할 수 있습니다.

 

3. 효과 훅의 의존성 메모이제이션:

useEffect와 같은 훅에서 의존성이 변경되지 않았음을 보장하여, 무한 루프를 방지하고 재렌더링 시 동일한 의존성 값을 유지하기 위해 메모이제이션을 사용합니다.

 

React Compiler의 초기 버전은 주로 업데이트 성능(즉, 기존 컴포넌트의 재렌더링 성능)을 개선하는 데 중점을 두고 있으며, 따라서 주로 첫 번째와 두 번째 사례에 집중하고 있습니다.

아래의 링크는 리액트 컴파일러 공식 문서입니다. 더 많은 자료는 아래의 링크에서 확인하실 수 있습니다.

https://react.dev/learn/react-compiler

반응형