https://www.youtube.com/watch?v=9CN9RCzznZc
How Next.js is delivering React’s vision for the future (Sam Selikoff)
내용 요약 (생략된부분 많음)
React의 최근 방향성에 대해 잘 모르거나 서버 컴포넌트, 서버 액션의 필요성에 대해 공감이나 이해가 부족하다면 꼭 확인해 보는 것을 추천한다. React 팀이 React의 핵심 가치를 폭넓게 제공하기 위해 어떤 고민을 하는지를 엿볼 수 있다.
서버 컴포넌트를 통해 데이터 페칭을 first class로 지원할 수 있게 되어 기쁘다.
사실 처음엔 이것에 대해 조금 회의적이였다.
클라이언트 방식 - SWR이나 React Query 등 사용할때 얻는 장점들이 있다.(생략)
근데 이걸 보고 내 생각이 바뀌었다.
별 내용은 아니지만 크게 와닿았다.
우리는 리액트를 왜 좋아할까?.
많은 사람들은 리액트가 레고를 다루는 것 같다고 한다.
레고 블럭은 갖가지 모양과 색상으로 제공되지만 결국 본질적으로 하나의 인터페이스로 귀결된다.
이 사실만 알면 뭐든 만들 수 있다.
composition - 이게 사람들이 리액트를 좋아하는 이유일 것이다.
근데 이건 UI 구성하는 부분에만 적용된다.
컴포넌트 자체는 composable 하지만 여기 데이터를 먹여야 한다.
SWR을 쓴다면 대충 이런식으로 구현될 것이다.
괜찮아 보인다.
이걸 서버 렌더링 하고싶다면 SWR같은걸 쓰기 어렵다.
근데 우리는 Next.JS 개발자니까 getServerSideProps
를 사용해 보자.
데이터 페칭은 서버측에서 실행될것이고 이걸 컴포넌트로 넘기면 데이터를 전달할 수 있다.
이런식으로 SSR이 가능해졌다 클라이언트측 로더는 브라우저 로더로 대체되고 데이터가 첫 렌더링에 바로 반영되었다.
근데 이렇게 하면 데이터를 prop을 통해 받고 composability를 잃게 된다.
이제 이 컴포넌트가 getServerSideProps
를 의존성으로 가지게 되기 때문이다.
Modal이나 Carousel을 앱 다른곳에도 적용하고 싶다고 하면 복붙할수 있겠지만 이 컴포넌트를 복붙하려고 하면 gSSP
도 신경써야 한다.
이러면 우리가 사랑하는 React의 프로그래밍 모델을 해친다.
이건 서버 측 API를 사용하게 되면 발생할수밖에 없는데 모든 앱은 서버측 API를 필요로 한다.
이걸 컴포넌트에 추가할 때마다 컴포넌트는 더이상 레고블럭이 아니게 된다.
이게 바로 근원적인 conflict 상황이다.
우리는 composability와 data fetching을 동시에 원한다.
서버측에서 DB에 직접 접근해서 컴포넌트를 렌더링할수있다면 어떨까
서버 컴포넌트를 사용하면 컴포넌트가 필요로 하는 모든 의존성이 컴포넌트 내에 존재하게 된다.
그러면 복붙해도 아무 문제가 없어지고 다시 레고블럭이 된다.
이 페이지를 새로고침할때 흥미로운 부분을 확인할 수 있다.
페이지의 핵심 섹션이 전체 화면을 차지하기 때문에, 아래의 부가적인 섹션은 바로 필요로 하지 않는다. 이 부분의 렌더링을 defer 해서 최초 렌더링을 빠르게 할수는 없을까.
이 부분을 Suspense
로 감쌌더니 fallback이 먼저 렌더링되고 그 후 섹션이 나타났다. 이는 모두 서버에서 진행되고 있다. 서버측 스트리밍 API를 제공할 수 있게 된 덕분이다.
그래서 우리가 어떤 해결책을 내놨을까.
이건 단순한 리액트 트리처럼 보이지만 까보면 많은 일들이 일어나고 있다.
이 안의 몇몇 컴포넌트들은 내부적으로 서버 API에 의존하고 있다.
이걸 감싸는 Modal과 Carousel 등은 브라우저 API에 의존하고 있다. 애니메이션이나 핸들러 등을 담당한다.
결과적으로 각각 서버측과 클라이언트측에서 돌아가는 컴포넌트들을 조합해 하나의 앱에서 유기적으로 composing 할수 있게 되었다.
일반적으로 '레고' 경험을 해치는 지점이 서버 코드를 작성할 때임을 고려하면 대단한 성과다. 이를 구현하려면 보통 프레임워크 API를 사용해야 하고.
결론은 이제 React가 두 고민을 모두 하나의 인터페이스 - component boundary - 로 래핑할 수 있는 방법을 제공한다.
이게 어떻게 가능할까?
이 경계선들 사이에서 많은 일이 일어나는데 Next가 서버 컴포넌트들을 서버측에서 돌리고 라우트, 코드 스플리팅, 클라이언트 컴포넌트의 shipping 등등을 진행한다. 사실상 두개의 앱이 돌아가는 것인데 우리가 느끼기에는 하나다.
아까 컴포넌트에 북마크 컴포넌트를 추가했다. 이런 핸들러가 있고 이런 API 엔드포인트가 있다고 해보자.
NewsStory
컴포넌트는 아직도 레고 블럭일까?
사실상 NewsStory
+ 어딘가에서 돌아갈 API 서버 의 조합이 되어버렸다.
이번에도 서버측 요구에 따른 디펜던시가 컴포넌트 경계 밖으로 나가버렸다.
이런식으로 하면 API 엔드포인트 의존성을 제거하고 그게 수행하던 작업을 직접 통합할 수 있다.
서버 액션은 API 엔드포인트를 다시 컴포넌트 경계 안으로 끌고 오는 역할을 한다. 서버 컴포넌트가 getServerSideProps
를 컴포넌트 경계 안으로 가져온것과 같은 맥락이다.
이게 새 리액트 패러다임 - 서버 컴포넌트와 서버 액션 - 이 제공하는 가장 매력적인 가치이며 Next는 이런 가치들을 App Router을 통해 잘 포장해냈다.
우리는 이제 모든 서버 측 concern을 컴포넌트 경계 안으로 통합할 수단을 갖췄다. 이제 컴포넌트는 다시 레고가 되었다.
React의 처음 10년은 이 과정을 서버 대신 클라이언트 측에서 구현하는 작업이라 볼 수도 있을 것이다.
초창기에는 탑레벨에 위치해야 하는 Modal 같은 컴포넌트를 만들려면 React 트리에서 벗어나서 렌더링할수밖에 없는 경우가 있었다.
혹은 웹소켓을 구독하는 컴포넌트를 만들려면 이걸 다른 어딘가 작성해야 하는 경우도 있었다.
즉 이런 요구사항들을 컴포넌트 경계 안에 잘 포장할 수 없는 상황이 있었다.
시간이 지나며 Portal
, useEffect
등의 API를 통해 이게 가능해졌다.
오늘날의 React는 이런 다양한 클라이언트측 UI 요구사항을 구현하기 위해 풍부한 생태계를 제공하고 있다.
이제는 서버 측 concern들에 대해 이런 과정이 일어나고 있는 것이다.
서버측 데이터를 불러오거나 액션 수행을 컴포넌트 내에서 할 수 있게 되었다. 다음 단계는 뭘까?
요즘 제공되는 클라이언트측 라이브러리들을 보면 도메인등에 한정되지 않고 그냥 agnostic하게 사용할 수 있다. 큰 고려 없이 NPM에서 받으면 바로 작동되고 끝이다.
앱에서 서버 API와 통신하는 부분들을 살펴보자. 예를 들어 Stripe 결제를 구현해야 한다 치면 셋업할게 많다. 가령 API 엔드포인트를 설정한다거나 시크릿, API키, 웹훅 등을 설정해야 한다거나.
<StripeCheckout />
<S3Uploader />
그런것들이 이렇게 단순해진다면 어떨까? 외부에 의존했던 모든 것들이 컴포넌트 경계 안으로 통합되는 것이다.
인증이나 CMS를 이렇게 간단하게 할 수 있다면 어떨까? 밑바닥부터 서버 컴포넌트와 서버 액션을 활용해 구성되게 된다면 오늘날 헤드리스 UI 라이브러리들과 마찬가지로 스타일링등은 자유롭게 하지만 내부적인 로직은 컴포넌트 경계 안에 번들되어있어 단순히 컴포넌트를 렌더링하고 props를 제공해주는것만으로 알아서 처리되고 신경쓸 필요가 없어지는 것이다.
요즘 UI 라이브러리들을 쓸때처럼 이렇게 쉽고 재미있게 React 앱에서 서버 측 코드를 작성할 수 있게 되는 거라면 나는 React의 미래가 너무 기대된다.