React _ 주목해야 할 React 기능

이승미·2022년 7월 28일
8

React가 버전 18로 업데이트 되면서 많은 부분이 변화하였는데, 가장 주목 할 만한 변화 사항은 React 18 버전이 더 이상 ReactDOM.render 을 지원하지 않는다는 것이다.

그 대신에 React 18 버전에서는 createRoot API 를 사용하게 되는데, 이 중 알아두어야 할 부분은 Concurrent Feature 이다. 그리고 이 기능에서 가장 주목해야 할 부분이 바로 Suspense 기능이다.

React 18 버전부터는 이 Suspense 기능을 이용해서 독립적으로 렌더링을 할 수 있도록 하였다. 이 Suspense 기능에 대해서 더 알아보도록 하자.

코드 분할 (Code Spliting)

Suspense 기능에 대해 본격적으로 알아보기 전에, 코드 분할에 대해서 먼저 알아보자. 코드 분할을 제대로 이해하면 Suspense 기능을 좀 더 쉽게 이해할 수 있다.

코드 분할

대부분의 React 앱은 Webpack 등과 같은 툴을 사용해 번들링을 한다. 이전에 블로깅 했듯이, 이렇게 하면 HTML 웹 페이지에 모든 JS를 쉽게 추가할 수 있기 때문이다.

그러나, 모던웹으로 점점 더 발전됨에 따라서, 점점 DOM을 다루는 정도가 정교해지고 JS 코드 자체도 무거워져서 번들링 시 특정 지점에서 코드를 해석하고 실행하는 정도가 느려지게 되었다. 이로 인해 나온 아이디어가 바로 코드 분할이다.

코드 분할의 핵심 아이디어는 다음과 같다.

어느 페이지에서 코드를 해석하고 실행하는 정도가 느려졌는지 파악해서 번들을 나눈 후에, 지금 필요한 코드만 불러오고 나중에 필요한 코드는 나중에 불러올 수 있도록 하자!

즉, 번들을 물리적으로 나누자는 것이다. 이렇게 하면 당장 필요하지 않은 코드를 따로 분리시킬 수 있어, 대규모 프로젝트 앱인 경우에 페이지의 로딩 속도를 개선할 수 있게 된다.

React 에서의 코드 분할

React는 기본적으로 SPA (Single Page Application) 이여서 사용하지 않는 모든 컴포넌트까지 한 번에 불러오기 때문에, 첫 화면이 렌더링될 때까지 시간이 오래 걸린다. 그래서 사용하지 않는 컴포넌트를 분리할 수 있는 코드 분할의 개념이 필요하다.

React에서는 코드 분할을 위해 이전까지 static import (정적 불러오기) 방식을 사용하다가 지금은 dynamic import (동적 불러오기)를 사용한다.

Static Import

// Static Import 방식은 차이르이 최상위에서 import를 이용해 라이브러리 및 파일을 불러왔다.
import moduleA from 'library';

from.addEventListener('submit', e => {
  e.preventDefault();
  someFunction();
});

const someFunction = () => {
 // 그리고 코드 중간에서 불러온 파일을 사용하였다.
}

Static Import 방식은 항상 import 구문을 문서의 상위에 위치시키고, 블록문 안에는 위치시킬 수 없다는 제한 사항이 있다.
번들링 시 코드 구조를 분석하여 모듈을 한 곳에 모으고 사용하지 않는 모듈을 제거하는 작업을 하는데, 이렇게 코드 구조가 간단하고 고정이 되어 있을 때만 이 작업이 가능하기 때문이다.

Dynamic Import

form.addEventListener('submit', e => {
  // 동적 불러오기를 사용하면 코드 중간에서 불러올 수 있게 된다.
  import('library.moduleA')
    .then(module => module.default)
    .then(someFunction())
    .catch(handleError());
});

const someFunction = () => {
  // moduleA를 여기서 사용하게 된다. 
}

이런 식으로 dynamic import 방식을 사용하여 불러온 moduleA 가 다른 곳에서 사용되지 않은 경우에, 사용자가 form을 통해서 양식을 제출한 경우에만 가져올 수 있도록 할 수 있다.

이 dynamic import 방식은 then 함수를 사용하여 필요한 코드만 가져오며, 가져온 코드에 대한 모든 호출은 해당 함수의 내부에만 있어야 한다.
이 dynamic Import는 React의 새 기능 중 하나인 React.lazy() 와 함께 사용할 수 있다. 아래에서 본격적으로 React.lazy()와 Suspense에 대해서 알아보자.


React.lazy()

React.lazy() 를 사용하면 dynamic import를 사용하여 컴포넌트를 렌더링할 수 있다. 이 React.lazy() 를 통해 컴포넌트를 동적으로 import하면 초기 렌더링 시간을 어느 정도로 줄일 수 있게 된다.

import Component from './Component';

// React.lazy로 dynamic import를 감싸준다.
const Component = React.lazy(() => import('./Component'));

React.lazy로 감싼 컴포넌트의 경우, 단독으로 쓰일 수 없고 React.suspense 컴포넌트의 하위에서 렌더링을 해야 한다.

React.suspense

React로 분기가 나누어진 컴포넌트를 React.lazy 를 통해 import 하게 되면 해당 하는 path로 이동할 때 컴포넌트를 불러오게 되는데 이 과정에서 로딩하는 시간이 발생하게 된다.

이 때, React.suspense를 사용하면 아직 렌더링이 준비되지 않은 컴포넌트가 있을 때 로딩 화면을 보여주고, 호딩이 완료되면 렌더링이 완료된 컴포넌트가 보여지게 된다.

// suspense 기능을 사용하기 위해서는 import 해와야 한다. 
import { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
         // Suspense 컴포넌트 하위에 여러 개의 lazy 컴포넌트를 렌더링시킬 수 있다. 
        <OtherComponent />
        <AnotherComponent />
      </Suspense>
    </div>
  )
}

Suspense 컴포넌트의 props인 fallback은 컴포넌트가 로드될 때까지 기다리는 동안 로딩 화면으로 보여 줄 React 엘리먼트를 받아들인다.

0개의 댓글