[react] RSC (feat.NextJS)

김학재·2023년 5월 30일
4

NextJS

목록 보기
2/3

NextJS를 공부중에 React Server Component (이하 RSC)에 대해서 공부하게 되었다.

2020년 12월에 출시된 기능이며, 22년 10월에 릴리즈된 NextJS 13 에서 app directory를 채택하면서 RSC를 지원하기로 했고, 23년 5월 5일에 릴리즈된 NextJS 13.4부터 모든 컴포넌트가 기본적으로 RSC가 되었다.

이 포스팅에서는 RSC가 무엇인지 그리고 왜 RSC를 사용하는지 정리해보려고 한다.


What?

React 18 전까지만 해도 react에서 애플리케이션을 렌더링하는 방식은 모두 client rendering이었다.

Next.js는 애플리케이션을 pages 단위로 나눈 뒤, 서버 단에서 HTML 페이지를 미리 렌더링 한 뒤 React로 하여금 클라이언트 단에서 hydrated 하는 방식을 가능하도록 했다. 그러나, 이 방식은 HTML 페이지가 상호작용이 가능하도록 하기까지 추가적인 JS의 로딩이 필요하게 됐다.

이를 보완하기 위해 등장한 개념이 바로 RSC이다. RSC는 client와 server의 장점을 모두 채택한 새로운 개념이다. RSC는 서버에서 한 차례 렌더링을 거친 뒤 클라이언트로 전달되게 된다.

Why?

RSC가 무엇인지는 알았는데 왜 사용하는 걸까?

RSC는 개발자로 하여금 server 인프라를 보다 효과적으로 활용할 수 있도록 한다. 데이터 가져오는 동작을 서버 단으로 이동해 데이터베이스에 가깝게 하면서, 클라이언트 JS 번들의 dependency를 유지하여 성능을 향상시킬 수 있다.

RSC의 활용을 통해 로딩 속도는 빨라지고, 클라이언트 사이드의 JS 번들 크기는 줄어든다. 기본 클라이언트 사이드 런타임은 애플리케이션의 크기 증가에 따라 증가하지 않는다. 오직 클라이언트 사이드에서 필요한 경우에만 추가적인 JS가 추가된다.

Next.JS에서 App Router가 Stable 단계로 돌입하고 release되면서, 모든 컴포넌트는 기본적으로 RSC가 되었다. 그러나 무조건 SSR이 아닌 SSR과 CSR의 장점을 모두 가지고 있으므로 client component도 같이 잘 사용해야 한다.

When?

그렇다면 우리는 어느 상황에서 RSC를 사용해야 할까?
when to use Server and Client component

위 표를 간단하게 요약하자면 말 그대로 SSR의 장점이 필요한 곳에서는 RSC, CSR의 장점이 필요한 곳에서는 Client Component를 활용하도록 나와있다.

RSC의 장점

Zero Bundle Size

RSC는 서버에서 이미 렌더링된 다음 클라이언트에게 직렬화(serialize)된 형태로 전달되기 때문에 클라이언트 사이드에서 추가적인 로드가 필요없게 된다.

Full Access to Backend

클라이언트 사이드에서 접근 불가능하던 데이터베이스에 손쉽게 접근할 수 있다. fs를 활용하거나 혹은 바로 데이터베이스에 접근할 수 있다.

Automatic Code Splitting

기존에 code splitting을 위해서는 lazy load 또는 dynamic import를 활용해야 했다.

RSC에서는 client component를 import하는 경우 자동으로 dynamic import가 적용된다.

No Client-Server Waterfalls

Server Component 이전에 데이터를 가져오는 방식은 아래와 같았다.

// Note.js
// NOTE: *before* Server Components

function Note(props) {
  const [note, setNote] = useState(null);
  useEffect(() => {
    // NOTE: loads *after* rendering, triggering waterfalls in children
    fetchNote(props.id).then(noteData => {
      setNote(noteData);
    });
  }, [props.id]);
  if (note == null) {
    return "Loading";
  } else {
    return (/* render note here... */);
  }
}

부모와 자식 컴포넌트가 모두 위 방식을 사용할 경우, 부모 컴포넌트의 데이터 로딩이 끝나기 전까지 자식 컴포넌트는 데이터를 로드할 수 없게 된다.

// Note.js - Server Component

async function Note(props) {
  // NOTE: loads *during* render, w low-latency data access on the server
  const note = await db.notes.get(props.id);
  if (note == null) {
    // handle missing note
  }
  return (/* render note here... */);
}

Server Component에서는 데이터를 가져오는 로직을 Server Side로 이동시켜서 요청에 대한 지연을 줄이고 성능을 개선할 수 있다. 또한, 필요한 컴포넌트에서 바로 데이터를 사용할 수 있도록 한다.


헷갈리고 생소했던 개념인 RSC가 무엇인지, 이를 사용해서 무엇을 달성할 수 있는지를 알 수 있는 기회였다. 왜 NextJS가 인기있는 프레임워크인지도 동시에 알 수 있었다. 빠른 변화 속도를 따라잡기 위해서는 꾸준히 공부를 해야겠다!

참고 자료

profile
YOU ARE BREATHTAKING

0개의 댓글