최신 앱들은 연구, 설계, 개발 및 테스트에 많은 시간이 필요합니다.
최신 앱을 만들기 위한 여러가지의 기술들이 존재하는데, 각각의 기술들은 특정한 문제를 해결하기 위해 존재하며, 그들만의 장단점이 존재합니다.
최신 앱을 만들기 위해서 묘책은 따로 존재하지 않습니다.
우리가 리액트로 개발을 할때, 우리는 요즘 사용되는 각각 기술들을 명명할수는 있겠지만, 제일 많이 사용되는 기술은 서버 사이드 렌더링과 클라이언트 사이드 렌더링입니다.
각각의 기술들은 앱을 개발하면서 발생되는 특정한 문제들을 해결해주고, 최신 앱들을 개발할때 제일 많이 사용되는 기술들입니다.
2020년이 끝나갈때쯤, 리액트 팀은 리액트 서버 컴포넌트라고 불리는 새로운 기술을 만들어 소개했습니다.
그때부터 리액트 커뮤니티 생태계에서는 이 서버 컴포넌트의 기능에 관한 장단점들이 논의 되었고, 앞으로 만들어질 리액트 앱들에 어떠한 영향을 끼칠수 있는가에 대한 주제로 이야기가 다루어져왔습니다.
우리는 이 글에서 어떻게 서버 컴포넌트가 리액트 앱들을 만들어가는 방식에 영향을 끼칠 것인지 다룰 것입니다.
리액트 서버 컴포넌트들에 대해서 배우기 이전에, 이 서버 컴포넌트를 배포 환경에서 사용하는것은 아직 시기상조라는 점을 염두해두어야 합니다.
리액트 팀은 이렇게 말합니다.
서버 컴포넌트를 사용함으로써, 개발자들이 전통적인 방식이지만 더 나은 성능을 제공 했던 서버 렌더링 방식과 클라이언트 사이드 렌더링이 갖고 있는 풍부한 상호작용성을 결합합으로써 더 나은 앱들을 만들수 있도록 합니다.
리액트 서버 컴포넌트들은 번들 사이즈에 전혀 영향을 끼치지 않습니다. 이러한 점은 리액트 앱들을 빌드하는 방식에 영향을 끼칠 것입니다.
서버 컴포넌트를 사용함으로써 번들 사이즈를 줄일 뿐만 아니라, 초기에 페이지 로딩 시간을 단축 시킬 수도 있습니다.
리액트 서버 컴포넌트들은 서버에서 렌더링 되고, 렌더링된 컨텐츠들만이 클라이언트 쪽으로 보내집니다.
import db from "database";
const Comment = (props) => {
const { id } = props;
const comment = db.comments.get(id);
return (
<div>
<h1>{comment.title}</h1>
<p>{comment.text}</p>
</div>
);
};
리액트 서버 컴포넌트들은 전형적인 리액트 컴포넌트처럼 보이지만, 서버 컴포넌트들은 추가적인 기능들을 더 가지고 있습니다. 예를 들어서
서버 컴포넌트는 microservices, 함수들, 데이터베이스들 같은 서버 데이터에 직접적으로 접근할 수 있습니다.
이러한 기능은 우리가 API에 직접적으로 접근할 필요 없이 컴포넌트 내에서 서버로 접근할 수 있도록 합니다.
또한 다양한 데이터 소스들과 동작하는 내부 API를 만들 수 있습니다.
서버 컴포넌트들은 컴포넌트 이름 뒤에 .server.js 라는 네이밍 컨벤션을 지킴으로써 만들어집니다.
예를 들어서 당신이 만약 note.js 라는 컴포넌트를 만들었다면, 그 컴포넌트의 파일명은 note.server.js 가 되어야 합니다.
이와 반대로 클라이언트 컴포넌트들은 파일 이름 뒤에 .client.js 를 붙임으로써 만들어집니다.
리액트 서버 컴포넌트들은 우리가 직면한 모든 문제들을 해결해주지는 않습니다.
리액트 서버 컴포넌트에서 불가능한 것들이 있는데, 예를 들면
우리는 서버 컴포넌트와 클라이언트 컴포넌트 모두에서 사용되는 훅들과 컴포넌트들을 만들 수 있습니다.
훅들은 컴포넌트들간의 상태를 공유하는데 매우 간단하고 강력한 방법이고, 서버 컴포넌트를 사용함과 동시에 훅들을 사용할 수 있습니다.
우리는 밑의 제한사항들을 따르고 있는지 확인해야합니다.
이러한 제한사항들을 따른다면, 우리는 서버와 클라이언트 컴포넌트 둘다 사용될수 있는 컴포넌트들과 hook을 만들 수 있습니다.
전통적인 리액트 컴포넌트는 클라이언트 사이드 렌더링이 이루어지는 클라이언트 컴포넌트 입니다.
클라이언트 컴포넌트는 state들을 관리할 수 있고, 브라우저 전용 API들을 사용할 수 있습니다.
서버 컴포넌트는 서버 컴포넌트나, HTML 요소, 아니면 클라이언트 컴포넌트를 렌더링 할 수 있습니다.
CommentLikeButton이라는 클라이언트 컴포넌트가 있다고 가정해봅시다.
우리는 이 클라이언트 컴포넌트를 서버 컴포넌트 내에서 불러와서 아무 문제 없이 사용할 수 있습니다.
import db from "database";
import CommentLikeButton from 'CommentLikeButton.client';
const Comment = (props) => {
const { id } = props;
const comment = db.comments.get(id);
return (
<div>
<h1>{comment.title}</h1>
<section>{comment.body}</section>
<CommentLikeButton />
</div>
);
};
서버 사이드 렌더링은 서버쪽에서 렌더링한 후에, 그 HTML파일을 클라이언트에게 보내고 브라우저 내에서 HTML이 렌더링 되는 것을 의미합니다.
서버 사이드 렌더링의 가장 중요한 2가지 이점이 있습니다.
서버 컴포넌트들은 서버쪽에서 렌더링 되는것은 맞지만, HTML 파일은 아닙니다.
서버 컴포넌트들은 클라이언트에게 특수하게 스트림 되는 형식을 사용해서 렌더링 되어집니다.
밑의 사진은 서버 컴포넌트가 렌더링 되어지는 방식입니다.
서버 컴포넌트가 우리의 컴포넌트들을 렌더링 하기 위해 사용하는 스트림은 특정한 기준은 없지만 JSON 형식처럼 보입니다.
서버 컴포넌트가 매우 강력하지만서도, 서버 컴포넌트는 SSR을 대체할수는 없습니다.
여기에는 우리가 분별해야할 몇가지 차이점들이 존재합니다.
SSR은 다시 렌더링 되어질순 있지만, 다시 렌더링 될때 전체 모든 HTML 페이지를 리렌더링 하고 app 상태를 잃게 됩니다. 하지만 서버 컴포넌트들은 언제든 리렌더링 될 수 있습니다.
서버 컴포넌트는 microservices나 함수나 데이터베이스 같은 서버 데이터에 접근 할 수 있습니다.
하지만 SSR은, 페이지 최상위에서 동작하는 getServerSideProps()를 사용해야합니다.
대부분의 경우에서, 우리가 서버 사이드 렌더링을 사용할 때는 초기 렌더링을 위해서 한번만 사용합니다.
서버 컴포넌트는 우리의 데이터를 리렌더 하기 위해서 여러번 재렌더링 될 수 있습니다.
우리는 주기적으로 우리의 서버 컴포넌트를 가져올 수 있으며, 서버는 우리의 클라이언트 컴포넌트에 있는 state를 손상없이 업데이트들을 불러옵니다.
웹 개발 환경에서 출시된 모든 새로운 것들은 우리가 개발하는 방식을 변화시키고, 미래에 최신 앱들을 빌드 할 것입니다.
개발자들은 자신들의 앱의 성능을 향상 시키기 위해서 물론 새로운 기술들을 살펴보아야하며, 리액트 서버 컴포넌트들은 최신 앱들을 만드는 과정에서 새로운 방식을 가져올 것입니다.
우리는 리액트 서버 컴포넌트가 서버 사이드 렌더링과는 다르다는 것을 알아야합니다.
우리는 우리가 원하는 만큼 우리의 데이터가 리렌더 될수 있도록 우리의 컴포넌트를 재렌더 하길 원할 것이고, 그것을 위해 특별한 형식을 사용합니다.
이러한 2가지의 기능들로 우리가 리액트 어플리케이션을 만드는데 전체 방식을 손쉽게 변화시킬 수 있습니다.