[React] Server component (RSC)
React.js 18 에 도입된 리액트 서버 컴포넌트는 서버에서 동작하는 리액트 컴포넌트를 의미합니다. Next가 권장하는 라우팅 방식인 app router의 기반이 되는 컴포넌트이기 때문에 app router 를 이해하기 위해서는 server component 에 대한 이해가 필요합니다.
server component
리액트는 클라이언트단만을 컴포넌트화하는 대신, server component라는 개념을 통해 서버 영역을 컴포넌트화합니다.
(출처: https://github.com/reactwg/server-components/discussions/4)
서버 컴포넌트의 등장으로 server component 에서 데이터를 직접 가져와 client component 로 데이터를 prop 하는 형식으로 server 영역과 client 영역이 구분되기 시작했습니다.
서버컴포넌트는 컴포넌트 렌더링을 클라이언트가 아닌 서버에서 수행합니다. 서버에서 동작하기 때문에 서버 사이드 데이터에 직접 접근할 수 있으며, 유저와의 상호작용을 추가할 수 없기 때문에 클라이언트 컴포넌트와 서버 컴포넌트를 적절히 사용하는 것이 중요합니다.
서버컴포넌트는 data fetching 측면에서 기존 클라이언트 컴포넌트에서 나타나는 문제점을 해결할 수 있습니다.
client-server waterfall 문제 해결 : 아래처럼 컴포넌트마다 다른 데이터 fetch 를 하려고 한다는 상황을 생각해봅시다.
function HomePage(){ return ( <ParentComponent> <ChildrenComponentOne/> <ChildrenComponentTwo/> <ParentComponent/> ) }
이 경우 부모 컴포넌트는 api 호출이 완료될때까지 렌더링되지 않고, 자식 컴포넌트들의 렌더링과 api 호출이 수행되지 않습니다.(waterfall 문제 -> 성능 저하)
중첩되는 컴포넌트가 많아질수록 client-server api 호출은 많아질 것이고, 호출에 대한 응답이 완료될 때 까지 기다리는 waterfall 문제는 더욱 심각해집니다.
//server component import dbConnect from 'db'; async function MyPost(props) { const {userId} = props; const userData = await dbConnect.users.get(userId); return ( <div> <div>{userData.post}</div> </div> ); }
다음은 server component 에서 데이터를 직접 fetch 하는 예시 코드입니다. server component 를 통해서 server-to-server로 데이터를 요청한다면 데이터 요청의 latency 를 줄일 수 있고, api 호출 없이 직접 DB 에 접근해 데이터를 가져올 수 있기 때문에 중첩되는 client-server api 호출을 제거할 수 있습니다.
js 번들 사이즈 줄이기
서버 컴포넌트는 렌더링을 서버에서 수행하기 때문에 클라이언트단의 번들 사이즈를 감소시킬 수 있습니다. (서버컴포넌트는 서버에서 수행된 결과를 전달하기 때문에 번들을 필요로하지 않음)
server component VS server side rendering
server component 와 server side rendering 개념은 혼동하기 쉬운 개념입니다. 하지만 둘은 다른 것..! (둘은 보완 개념에 가깝습니다.)
(Next.js 에서의 서버사이드렌더링을 기준으로) 서버사이드렌더링은 서버에서 미리 정적인 html 을 생성해주어 초기 랜딩 시 사용할 수 있도록 합니다.
하지만 서버 컴포넌트는 서버 영역을 컴포넌트화한것으로, 클라이언트에서는 보이지 않도록, 서버에서만 실행되도록 하는 컴포넌트입니다. (ssr 은 코드는 js 번들에 포함되어 클라이언트로 전송됨)
client component 와 server component 적절히 사용해보기
server component 내에서 client component import -> 가능
client component 내에서 server component import -> 불가
위에서 언급한 것 처럼 서버 컴포넌트에서는 유저 인터렉션 관련 작업을 수행할 수 없습니다. 따라서 서버 컴포넌트 데이터를 그 안에서 import 한 클라이언트 컴포넌트로 props 로 전달하는 방식을 사용해야 합니다. (Next.js 는 client component 를 leaf node 로 둘 것을 권장)
이런 패턴으로 배치한 컴포넌트는
1. 모든 서버 컴포넌트 렌더링
2. 클라이언트단에서 리액트가 클라이언트 컴포넌트와 1의 결과(slot) 를 렌더링, 즉 합침
의 과정으로 동작합니다.
위에서 user 의 post 를 보여주는 예시 코드를 보여줬는데, 이와 같이 유저 인터렉션이 필수적이지 않은 상황에서는 server component 를 활용하는 것이 적절하고, 글을 작성하거나 업데이트하는 등의 상호작용이 필요한 경우에는 useState 등의 hook을 사용할 수 있는 client component 를 활용해야 합니다.
참고