들어가며
React 공식 블로그나 Next.js App Router 중심의 흐름을 보면 최근 React 생태계는 서버 중심 렌더링 구조를 적극적으로 활용하는 방향으로 변화하고 있는 것 같습니다. Server Components, Streaming UI, Server Actions 같은 개념들의 등장 이후, 기존에 익숙했던 CSR(Client Side Rendering) 중심의 개발 방식이 Server Components 기반 구조와 공존하는 방향으로 흐르는 추세인 것 같습니다. 이런 흐름은 React 19 이후에 좀 더 명확해졌는데요, 근래의 React 동향에 대해서 정리해 보았습니다.
서버 중심 구조로 변화하는 React
Server Components 중심으로 변화해온 흐름
React 공식 블로그를 보면 몇 가지 공통적으로 등장하는 키워드들이 있습니다.
- Server Components
- Streaming UI
- React Compiler
- Server Actions
이 키워드들의 등장 의미는 React가 단순히 컴포넌트를 렌더링 하는 수준을 넘어, 서버와 클라이언트를 함께 고려하는 애플리케이션 구조로의 변화를 공식으로 삼고 있다는 점입니다. 특히 Next.js App Router 이후 이러한 흐름은 React 생태계 전반으로 빠르게 확산되고 안정화 및 정착되고 있습니다.
CSR 중심 구조의 한계
이러한 변화는 단순히 React 팀의 취향 변화라기보다는, 현대 웹 애플리케이션 규모가 커지면서 자연스럽게 등장한 흐름에 가까워 보입니다. CSR 방식에서는 프로젝트 규모가 커질수록 클라이언트가 처리해야 하는 JavaScript 양 역시 함께 증가하게 됩니다. 자연스럽게 번들 크기와 hydration 비용도 커지게 되고, 초기 렌더링 성능 문제로 이어지는 경우도 많았습니다. 특히 모바일 환경에서는 더욱 체감이 크기도 했고요.
전통적 React 프레임워크에서는 React Query나 SWR 같은 라이브러리를 활용해 클라이언트에 데이터를 가져오는 방식이 일반적이었습니다.
물론 이러한 방식은 캐싱이나 상태 관리 측면에서 많은 장점이 있었지만, 결국 브라우저에서 JavaScript가 실행된 이후 데이터를 요청하는 구조라는 점은 크게 달라지지 않았습니다.
const { data, isLoading } = useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
})
하지만 서버 컴포넌트 기반에서는 데이터를 가능한 서버에서 먼저 가져오고, 클라이언트에는 필요한 UI만 전달합니다. 클라이언트로 전달되는 JavaScript 양을 줄일 수 있다는 점은 초기 렌더링 성능 측면에서도 장점이 있습니다.
async function Page() {
const data = await fetch(...)
return <Component data={data} />
}
useEffect 기반 데이터 fetch 흐름은 결국 “렌더링 이후 데이터를 가져오는 구조”에 가까웠기 때문에 초기 사용자 경험 측면에서는 아쉬움이 존재하기도 했습니다. 되돌아보면 늘 사용자 경험을 고민해야 하는 XE 그룹 입장에서는 어떻게 해야 useEffect를 최소한으로 사용할 수 있을지도 고민 대상이었습니다.
React가 서버 중심 구조를 강화하는 이유도 결국 이런 문제들을 해결하기 위한 방향으로 볼 수 있을 것 같습니다. React 18 시기에 제시되었던 RSC 개념은 App Router를 거치며 React 19 이후 조금 더 안정화되었고, 최근에는 실제 생태계에서도 점진적으로 적용 범위가 넓어지고 있는 것 같습니다.
Streaming UI와 점진적인 렌더링 변화
Streaming UI 역시 현재 React 흐름에서 자주 등장하는 개념 중 하나입니다. 개념 자체는 등장한 지 꽤 되었지만 App Router 이후 적극적 사용 단계로 자리 잡았습니다.
기존 SSR(Server Side Rendering) 방식에서는 서버에서 페이지에 필요한 대부분의 HTML을 생성한 이후 브라우저로 전달합니다. 이 방식은 페이지 규모가 커질수록 페이지 렌더링 시간이 오래 걸렸고, hydration 과정 역시 부담이 될 수 있었습니다.
Streaming 기반 렌더링은 이러한 흐름을 조금 더 잘게 나누어 처리할 수 있도록 변경되었습니다.
준비된 UI부터 먼저 사용자에게 전달하고, 이후 필요한 부분들을 점진적으로 이어서 렌더링 하는 방식입니다. Suspense boundary를 기준으로 렌더링 흐름을 분리할 수 있게 되면서, 페이지 전체가 준비될 때까지 기다리지 않고도 먼저 준비된 영역부터 사용자에게 보여줄 수 있게 되었습니다. App Router 이후 이러한 Streaming 기반 렌더링 구조 역시 실무에서 점점 자연스럽게 사용되고 있는 것 같습니다.
React Compiler가 의미하는 것
React Compiler는 메모이제이션과 렌더링 최적화 일부를 컴파일 단계에서 자동으로 처리해, 개발자가 useMemo나 useCallback 같은 최적화 코드를 직접 관리해야 하는 부담을 줄여줍니다.
기존 React에서는 성능 최적화를 위해 개발자가 직접 useMemo, useCallback, memo 등을 관리해야 하는 경우가 많았습니다. 이러한 방식은 개발자에게 비교적 많은 제어권을 제공한다는 장점이 있었지만, 반대로 렌더링 최적화까지 직접 고민해야 한다는 부담도 함께 존재했습니다. 성능 최적화를 위해 코드가 점점 복잡해지거나, 불필요한 부분까지 최적화를 적용하면서 오히려 역효과가 발생하는 경우도 한 번쯤은 다들 있었을 겁니다.
또한, Vue나 Svelte처럼 경쟁 프레임워크들이 “React는 너무 복잡하고 어렵다”라는 점을 기반으로 성장한 부분도 어느 정도 있다는 점, 서비스 규모가 커지고 UX에 대한 기대 수준도 높아졌으며 모바일 환경에서의 성능 확보도 기본이 되고 있다는 점에서 React Compiler의 등장은 이러한 흐름의 자연스러운 결과로 보입니다.
*React Compiler는 2025년 10월에 1.0 stable 버전이 공식 릴리즈 되었으며 점진적 도입을 제안했습니다.
마치며
XE 그룹은 대체적으로 Next.js App Router 방식을 선호하지만 다른 프레임워크로도 개발하는데요, 이런 프레임워크 생태계 흐름에 대해서 살펴보니 흥미로웠습니다. AI가 코드를 생산해 내는 지금 같은 시대에서는 거대한 생태계와 생태계가 어떤 흐름을 타고 있는지가 생각보다 중요하더라고요. 기회가 되면 다른 프레임워크의 생태계도 확인해 보면 재미있을 것 같습니다.

