React를 벗어나보자, 그리고 렌더링을 다시 보자 feat. jsp jquery Next..

created:
last-updated:

렌더링의 출발점

JSP와 전자정부프레임워크 기반의 전통적인 방식은 렌더링의 출발점이 서버다. 요청이 들어오면 서버는 데이터를 조회하고 템플릿을 실행해서 HTML을 완성한 뒤 브라우저로 내려보낸다. 이 HTML은 단순한 골격이 아니라 이미 의미를 모두 가진 결과물이고, 브라우저는 그것을 실행하는 게 아니라 그대로 그린다. 렌더링이라는 행위가 서버에서 끝난다.

반대로 React에서는 출발점이 클라이언트다. 서버는 주로 JSON 형태의 데이터만 전달하고, 실제 화면은 브라우저에서 실행되는 JavaScript가 구성한다. HTML은 결과가 아니라 계산의 중간 산물에 가깝고, 화면은 실행 과정 속에서 만들어진다.

Ajax의 위치와 역할

전통적인 SSR 구조에서 Ajax는 어디까지나 보조적인 도구다. 초기 화면은 서버가 완성해서 내려주고, 이후 일부 상호작용이 필요할 때만 비동기 요청을 통해 데이터를 가져와 DOM 일부를 교체한다. 즉 전체 구조는 여전히 서버 중심이고 Ajax는 부분 갱신을 위한 최적화일 뿐이다.

반면 React에서는 Ajax가 기본적인 데이터 흐름이다. 초기 렌더링 이후에도 모든 데이터는 비동기로 가져오고, 그 결과는 상태로 저장되며 UI 전체가 다시 계산된다. Ajax는 더 이상 보조가 아니라 시스템의 중심이 된다.

상태를 바라보는 방식

JSP 기반 구조에서는 상태가 분산된다. 서버 세션에 일부가 있고, 브라우저 DOM 자체가 또 하나의 상태이며, 스크립트 내부 변수도 상태 역할을 한다. 이 상태들은 서로 느슨하게 연결되어 있기 때문에 흐름을 추적하기 어렵다.

React에서는 상태가 중심이다. 화면은 상태의 결과로 정의되고, 상태가 바뀌면 UI가 다시 계산된다. DOM은 상태의 결과일 뿐 직접 관리 대상이 아니다. 이 차이 때문에 복잡도가 쌓이는 방식 자체가 달라진다.

UI를 구성하는 방식

JSP에서는 템플릿 엔진을 통해 문자열 기반으로 HTML을 생성한다. 반복문과 조건문을 통해 서버에서 한 번 HTML을 만들고 나면 그 결과는 고정된다. 이후 변경이 필요하면 다시 요청하거나 일부를 교체해야 한다.

React에서는 컴포넌트가 UI의 기본 단위다. 컴포넌트는 상태를 입력으로 받아 JSX를 반환하는 함수처럼 동작하고, 상태가 바뀔 때마다 다시 실행된다. UI는 생성되는 것이 아니라 계속 재평가된다.

DOM을 다루는 방식

jQuery 기반에서는 DOM을 직접 조작한다. 특정 요소를 선택하고 내용을 바꾸거나 새로운 노드를 삽입하는 식으로, 어떻게 변경할지를 명령형으로 기술한다.

React에서는 DOM을 직접 다루지 않는다. 어떤 상태에서 어떤 UI가 되어야 하는지를 선언하면, 그 차이를 계산해서 필요한 최소한의 변경만 적용한다. 개발자는 결과를 정의하고 과정은 위임한다.

사고 방식의 차이

JSP 세계에서는 “이 데이터를 어떻게 HTML로 만들어서 내려보낼까”가 중심 질문이다. 렌더링은 서버에서 끝나는 작업이다.

React 세계에서는 “이 상태라면 화면은 무엇이어야 하는가”가 중심 질문이다. 렌더링은 한 번의 이벤트가 아니라 상태 변화에 따라 계속 반복되는 계산이다.

확장성과 유지보수

전통적인 방식은 초기에는 단순하고 빠르게 개발할 수 있지만, UI가 복잡해질수록 상태가 흩어지고 DOM 조작이 얽히면서 유지보수가 어려워진다. 특히 Ajax가 늘어날수록 상태 불일치가 발생하기 쉽다.

React는 초기에 구조를 잡는 비용이 있지만, 상태와 컴포넌트 단위로 분리되기 때문에 규모가 커질수록 안정적이다. 변경의 영향 범위를 예측할 수 있고 재사용이 가능하다.

현대적인 중간 형태

이 둘은 완전히 분리된 채로 존재하지 않는다. Next.js같은 프레임워크는 초기 렌더링을 서버에서 수행하고 이후에는 클라이언트에서 이어받는다. 이 구조는 서버와 클라이언트가 렌더링을 나눠 갖는 형태다. 다만 여기서의 SSR은 전통적인 의미와 다르다. 서버가 화면을 완성하는 것이 아니라, 클라이언트 렌더링을 앞당겨서 미리 계산해주는 역할에 가깝다.

전통적인 SSR은 무엇이었나

JSP 기반 구조는 가장 정직한 의미의 SSR이다. 서버는 데이터를 조회하고 템플릿을 실행해 HTML을 완성한다. 이 HTML은 이미 완결된 문서이며, 클라이언트는 그것을 소비할 뿐이다. 이 구조에서는 렌더링이 서버에서 끝난다. 이 점에서 JSP는 단순한 템플릿이 아니라 서버 중심 렌더링 시스템이다.

왜 이게 ‘진짜 SSR’처럼 느껴지나

요즘의 SSR은 React 컴포넌트를 서버에서 한 번 실행해 HTML로 만드는 방식이다. 즉 클라이언트 코드를 서버에서 재생산하는 구조다. 반면 JSP는 애초에 UI가 서버 언어로 작성되어 있다. React SSR은 hydration이 필요하지만 JSP는 필요 없다. 이어받을 클라이언트 상태가 없기 때문이다. 그래서 JSP가 더 “순수한 SSR”처럼 느껴진다.

구 방식에서 Ajax가 등장한 이유

전통적인 SSR은 요청마다 전체 화면을 다시 그린다. 명확하지만 인터랙션이 많아질수록 비효율적이다. 그래서 일부만 갱신하기 위해 Ajax가 등장한다. 하지만 이는 렌더링 패러다임을 바꾼 것이 아니라 단순한 최적화다. 서버 중심 구조는 그대로 유지되고, 클라이언트가 일부를 덮어쓰기 시작했을 뿐이다.

왜 이 구조는 점점 무너졌을까

Ajax가 도입되면서 상태가 분산된다. 서버 상태, 클라이언트 변수, DOM 상태가 서로 어긋나기 시작한다. 이 세 가지가 일관되게 유지되지 않으면 화면은 점점 예측 불가능해진다. 코드가 늘어날수록 원인을 설명하기 어려워지고, 유지보수가 급격히 어려워진다. (그래도 여전히 많이씀.. React보다 많이 쓰는 것 같음)

React는 무엇을 바꾼 것인가

React는 DOM 조작 방식을 개선한 것이 아니라 렌더링의 기준을 바꿨다. HTML을 결과로 보지 않고 상태의 함수로 본다. 더 이상 어떻게 바꿀지를 고민하지 않고, 어떤 상태에서 어떤 UI가 나와야 하는지만 정의한다. 렌더링은 이벤트가 아니라 지속적인 계산이 된다.

SSR의 의미가 어떻게 변했는가

전통적인 SSR에서는 SSR이 곧 렌더링이었다. React 이후 SSR은 초기 화면을 빠르게 보여주기 위한 전략이 된다. 렌더링의 주체는 여전히 클라이언트이며, 서버는 시작점을 앞당겨주는 역할을 한다. 이로 인해 서버와 클라이언트의 관계가 역전된다.

React 이후, 다시 서버로 돌아오는 흐름

클라이언트 중심 구조는 번들 크기, 초기 로딩, SEO 문제를 낳는다. 그래서 일부를 다시 서버로 돌리려는 시도가 등장한다. 이 흐름 속에서 Next.js가 등장한다. 하지만 이는 과거로의 회귀가 아니라 새로운 형태의 분배다.

Next.js가 하는 일: 렌더링의 타이밍을 옮긴다

Next.js는 서버에서 HTML을 만들어주지만, 그 HTML은 끝이 아니라 시작이다. 클라이언트가 이를 이어받아 상태 기반으로 다시 활성화한다. 이 과정이 hydration이다. 따라서 이는 전통적인 SSR이 아니라 클라이언트 렌더링을 앞당긴 구조다.

React Server Components: 더 근본적인 변화

React Server Components는 컴포넌트 실행 위치 자체를 나눈다. 일부 컴포넌트는 서버에서만 실행되고 클라이언트로 내려가지 않는다. 서버는 데이터를 처리하고 UI 조각을 만들어 전달하며, 클라이언트는 인터랙션을 담당한다. 렌더링이 컴포넌트 단위로 분해된다.

JSP와의 묘한 재접점

RSC는 서버가 UI를 만든다는 점에서 JSP와 닮아 보인다. 하지만 JSP는 전체를 서버가 만들고 요청 단위로 끊기며, RSC는 일부를 서버에서 만들고 컴포넌트 단위로 나뉜다. 또한 전체 구조는 여전히 React 트리 안에 있다. 이는 회귀가 아니라 재구성이다.

렌더링이 “장소”에서 “레이어”로 바뀐다

과거에는 렌더링이 어디서 일어나는지가 중요했다. 이제는 어떤 레이어에서 어떤 계산을 하느냐가 중요하다. 데이터에 가까운 로직은 서버에서, 인터랙션은 클라이언트에서 수행된다. 렌더링은 위치가 아니라 역할로 나뉜다.

“상태”의 경계가 다시 정의된다

JSP에서는 상태가 서버에 있었고, React에서는 클라이언트로 이동했다. RSC에서는 상태가 다시 분리된다. 서버 상태와 클라이언트 상태가 각자의 영역에서 관리되고, 직렬화된 데이터로 연결된다. 모든 상태를 클라이언트로 가져올 필요가 없어진다.

결국 어디로 왔나

JSP는 서버에서 모든 것을 렌더링했고, React는 이를 클라이언트로 옮겼다. Next.js와 React Server Components는 이 둘을 다시 나누되, 훨씬 더 작은 단위로 분해한다. 렌더링은 페이지가 아니라 컴포넌트 단위로 쪼개진다.

정리

JSP는 서버가 화면을 완성하는 세계이고, React는 상태로 화면을 계산하는 세계다. 그리고 Next.js와 React Server Components는 이 둘을 절충하는 것이 아니라 렌더링을 분산된 계산으로 재정의한다. 이제 화면은 한 번 만들어지는 결과물이 아니라, 여러 위치에서 나뉘어 계산되는 과정이다.