개발하는SM

[React] 리액트가 작동하는 방식과 성능 최적화 테크닉 본문

Web/Front-End

[React] 리액트가 작동하는 방식과 성능 최적화 테크닉

개발하는SM 2023. 4. 5. 16:09

서론

리액트 컴포넌트 내부의 상태값이 변경될 때, 어떤 식으로 리액트가 동작하여 실제 DOM 을 변경해주는 것일까?

리액트 실행 성능을 최적화 할 수 있는 방법은 어떤 것이 있는지 알아보자.


리액트가 동작하는 방식

리액트 컴포넌트에서는 props, state, context 를 이용하여 상태값을 관리할 수 있으며,

상태값이 변경될 때마다 이 변경된 상태값을 포함하고 있는 컴포넌트는 재실행된다.

해당 컴포넌트의 하위에 있는 컴포넌트들도 모두 재실행되며, 

이 때 리액트는 단순히 최신 평가의 결과값을 가져와서 직전 평가와 비교한다.

그리고 확인된 모든 차이점을 ReactDOM 에 전달하며, ReactDOM 은 이 변경사항을 실제 브라우저의 DOM 에 적용한다.

 

그런데 이렇게 상태 값이 바뀔 때마다 모든 하위 컴포넌트를 재실행하는 것은 너무 비효율적이다.


리액트 성능 최적화 테크닉 

모든 자식 컴포넌트를 재실행하는 것은 비효율적이다.

그럼 변경이 필요한 자식 컴포넌트만 재실행 하라고 리액트에게 알려줘야 한다.

 

React.memo 를 사용하면 함수형 컴포넌트를 최적화 할 수 있다.

사용법도 간단하다. 아래와 같이 export 할 때 컴포넌트 이름을 React.memo로 감싸주기만 하면된다.

"리액트야, 해당 컴포넌트의 props 가 변경된 경우만 재실행해줘" 라고 명령하는 효과이다.

React.memo 사용 예시

React.memo 는 파라미터로 주어진 컴포넌트에 어떤 props 가 입력되는지 확인하고,

입력되는 모든 props 의 신규 값을 확인한 뒤 이를 기존의 props 값과 비교하도록 리액트에게 전달한다.

 

그런데, 이렇게 최적화가 가능하다면 왜 모든 컴포넌트에 적용하지 않을까?

--> 최적화에는 비용이 발생하기 때문이다. 기존의 props 와 새로운 props 를 비교하는 비용,,

 

React.memo 가 하는 것은 === 연산자로 기존의 값과 새로운 값을 비교하는 것이다.

따라서 primitive value 가 아닌 배열, 객체, 함수를 비교하는 경우 매번 값이 변경되었다고 판단하게 된다.

함수나 배열의 경우, 아래와 같은 방법으로 리액트에게 저장하고 있으라고 명령할 수 있다. ( 매 실행마다 재생성되지 않도록 )

--> 함수의 경우, useCallback을 이용해서 매번 동일한 함수를 재생성 할 필요 없다고 React 에 알려줘서 해결 할 수 있다.

--> 배열의 경우, useMemo 훅을 이용해서 React 가 값을 기억하도록 할 수 있다.

 

자바스크립트에서 함수는 클로저이다.

useCallback 함수를 사용해서 함수를 저장하는 시점에 내부에서 사용하지만 외부에서 정의된 값을 함수에서 사용하는 경우, 

저장하는 시점에 고정된 값을 함수로 저장함.

그러므로 useCallback 함수 호출 시 두 번째 인자로  dependency 배열을 넘겨줘야 하며,

dependency 배열에 해당 값(내부에서 사용하지만 외부에서 정의된 값)을 추가하여 해당 값이 변경되면 함수를 다시 저장하도록 해야한다. 

아래 코드를 예로 들면, useCallback() 을 호출하여 함수를 저장하는 시점의 allowToggle 값이 같이 저장되므로

allowToggle 값이 변경될 때마다 함수를 다시 저장하도록 dependency 배열에 allowToggle 값을 넣어주어야 한다.

useCallback() 을 사용한 함수 최적화


정리

리액트는 특정 컴포넌트의 상태값이 변경될 때마다 해당 컴포넌트와 해당 컴포넌트가 포함하고 있는 모든 자식 컴포넌트를 재실행한다.

재실행한 결과값과 이전 결과값을 비교하여 그 차이만을 실제 DOM 에 반영한다.

그런데 상태값이 변경될 때마다 모든 하위 컴포넌트를 재실행하는 것은 비효율적이며 이러한 비효율을 해결하기 위해

React.memo 와 useCallback(), useMemo() 를 사용하여 리액트에게 특정 경우 ( 컴포넌트에 전달되는 prop 에 변경이 있거나 상태값이 객체에 영향을 주는 경우 ) 에만 컴포넌트를 재실행하거나 객체를 새로 생성하도록 명령할 수 있다.


참조

https://www.udemy.com/course/best-react/