Remix v3 - 복잡해진 리액트 생태계의 판도를 바꿀 새로운 물결

November 22, 20256 minutes

Remix는 가장 인기 있는 리액트 패키지 제작자들이 만든, 리액트 생태계의 언더독 같은 웹 프레임워크인데요.

며칠 전 ‘Remix Jam 2025’ 행사에서 라이언과 마이클이 Remix v3를 살짝 공개했습니다.

아직 공식 블로그 글이나 문서는 전혀 없는 상태거든요.

그래서 공개된 내용을 바탕으로 Remix v3가 도대체 무엇인지, 어떤 변화를 가져올지 제가 한번 정리해 보려고 합니다.

Remix v3 - 복잡해진 리액트 생태계의 판도를 바꿀 새로운 물결
Remix v3 - 복잡해진 리액트 생태계의 판도를 바꿀 새로운 물결

먼저 과거를 돌아보면, Remix v1은 데이터 로딩과 서버 사이드 렌더링을 관리하는 리액트 프레임워크였는데요.

이 버전의 가장 큰 업적은 바로 마케팅 웹사이트였다고 할 수 있습니다.

초기 Remix는 Next.js의 독점적 지위에 대항할 수 있는 최초의 진정한 경쟁자로 여겨졌기에 아주 흥미로웠거든요.

하지만 Remix v2는 정체성과 메시지 전달에 어려움을 겪었습니다.

제작자 중 한 명은 “Remix v2는 리액트 라우터 v6 기능을 더 편리하게 사용할 수 있게 해주는 Vite 플러그인이다"라고 설명하기도 했는데요.

이건 확실히 Vercel의 막강한 마케팅 기계를 이길 수 있는 방법은 아닙니다.

사용자는 분명히 있었지만, 넥스트의 시장 점유율에 흠집을 낼 만한 성장세를 보여주지는 못했거든요.

그런데 이번 Remix v3는… 느낌이 아주 다릅니다.

웹 개발 전반의 정서 변화를 대변하고 있으며, 충분히 주목할 만한 가치가 있어 보이는데요.

그 이유를 이해하려면 현재 모던 리액트의 상태를 먼저 살펴봐야 합니다.

모던 리액트의 현주소

2025년 현재, 리액트는 정말 복잡하게 느껴지는데요.

‘리액트 서버 컴포넌트(RSC)‘는 서버에서 컴포넌트를 렌더링하고 클라이언트에서 하이드레이션(hydration)하는 훨씬 정교한 방법을 도입했습니다.

하지만 무엇이 허용되는지에 대한 규칙이 너무 미묘하고 까다롭습니다.

서버 컴포넌트는 이제 비동기(async)로 정의할 수 있고 클라이언트 컴포넌트에 데이터를 전달할 수 있지만, 모든 종류의 데이터를 보낼 수 있는 건 아니거든요.

게다가 일반적인 서버 사이드 함수를 마법 같은 RPC 액션을 통해 클라이언트에서 사용할 수도 있게 되었습니다.

결국 개발자들은 ‘use client’와 ‘use server’의 차이를 공부해야만 하는 상황이죠.

특히 거대한 앱에서의 속도는 공통적인 우려 사항이 되었는데요.

Svelte 같은 프레임워크는 가상 DOM 비교를 건너뛰고 요소를 업데이트하는 가장 효율적인 직접적인 방법을 제시하면서도, 여전히 선언적인 모습을 유지했습니다.

이에 대응해 리액트 팀은 메타(Meta) 내부에서 거의 8년 동안 준비해 온 프로젝트인 ‘리액트 컴파일러’를 공개했거든요.

이 컴파일러는 컴포넌트와 훅을 자동으로 메모이제이션(memoization)하는 방식으로 작동합니다.

하지만 미묘한 버그를 만들 수 있기 때문에 모든 컴포넌트에 적용되는 건 아닙니다.

이제는 ‘use memo’와 ‘use no memo’ (혹은 혼란을 더하는 ‘use forget’, ‘use no forget’ 같은 별칭들)를 신경 써야 하는 상황이 되어버렸습니다.

리액트의 핵심 API 범위는 계속해서 커지고 있는데요.

웹 앱의 반응성을 높이기 위해 서스펜스(Suspense), startTransition, useDeferredValue, useActionState 같은 비동기 렌더링 API들이 추가되었습니다.

이제 덜 급하지만 비용이 많이 드는 컴포넌트 트리 업데이트보다 사용자 상호작용을 우선시할 수 있게 되었지만, 개발자는 ‘활성(active)’ 상태와 ‘대기(pending)’ 상태를 직접 추론해야만 하거든요.

다른 새로운 API들도 복잡하고 틈새시장용으로 보이기 십상입니다.

‘useEffectEvent’ 문서를 한번 보세요 (클릭하기 전에 무슨 기능을 할지 한번 맞춰보시는 것도 좋겠네요).

아마 쉽지 않을 겁니다.

물론 누구도 개발자들에게 이 기능들을 쓰라고 강요하지는 않는데요.

사실 공식 ‘create-react-class’ npm 패키지를 사용하면 믹스인을 쓴 가장 오래된 방식의 ‘createReactClass’도 여전히 잘 작동합니다.

오늘날에도 그런 스타일의 리액트를 사용할 수 있고, 새로운 최신 기능을 굳이 도입하지 않아도 되거든요.

하지만, 실제로는 어느 정도 강요받는 느낌을 지울 수 없습니다.

이런 기능들이 Next.js를 통해 개발자들의 목구멍으로 억지로 밀어 넣어지고 있기 때문인데요.

리액트 자체는 프레임워크가 되려는 시도를 포기했습니다.

빠르게 변하는 자바스크립트 툴링을 따라잡는 건 너무 힘든 일이었고, 페이스북은 오픈소스로 공개할 가치가 없는 그들만의 설정을 가지고 있었기 때문이죠.

Next.js 자체도 페이지 라우터에서 앱 라우터로 넘어가는 고통스러운 과도기를 겪으며, 최신 기술을 쫓던 개발자들에게 큰 상처를 남겼습니다.

API의 잦은 변경뿐만 아니라, Next.js는 Vercel로 인해 또 다른 복잡성 계층을 가지게 되었는데요.

버셀은 풀스택 넥스트 앱을 그들만의 특별한 방식으로 배포합니다.

어떤 코드는 브라우저에서 돌고, 어떤 건 AWS 람다에서 돌고(3배나 비싼 가격으로), 또 어떤 건 그들의 독자적인 워커 런타임에서 돌아갑니다.

특히 ‘미들웨어’라는 용어는 개발자들에게 수십 년치의 혼란과 좌절을 안겨준 가장 큰 거짓말 중 하나일 것입니다.

이 모든 것들이 그냥… 너무 과하다고 느껴지는데요.

사실 이러한 기능과 프레임워크가 해결하려는 문제점을 설명하는 데만 해도 댄(Dan)이 여러 컨퍼런스와 블로그 글을 써야 했을 정도였습니다.

물론 이해하는 사람들은 이해합니다.

RSC, 서스펜스, 리액트 컴파일러는 정말 강력하고, 일부 기업이 겪는 실제 문제들을 해결해 주거든요.

설상가상으로, LLM(대규모 언어 모델)들은 리액트를 잘 다루지 못하는데요.

앱을 만들어달라고 하면 다들 리액트를 집어 들지만, 결과물은 ‘useEffect’의 끔찍한 잡탕이거나 미묘한 버그를 피하기 위한 랜덤 한 편법들로 가득 차 있습니다.

Remix v3의 등장

이런 복잡함과 좌절감 속에서 Remix v3가 태어났습니다.

Remix Jam 녹화 영상을 보시거나 제작자 두 명의 X(트위터) 계정을 훑어보시면 감이 오실 텐데요.

프론트엔드에서 Remix는 여전히 JSX를 사용하지만, 리액트 런타임은 없습니다.

리액트처럼 상태(state)를 추적하지 않고, 대신 개발자가 this.update() 함수를 호출하여 뭔가 변경되었다고 Remix에게 알리는 방식을 취하거든요.

명시적인 상태 대신 클로저에 캡처된 변수 같은, 말 그대로 아무거나 사용할 수 있습니다.

function Counter(this: Remix.Handle) {
  // 상태는 그냥 클로저일 뿐입니다
  let count = 0;

  return () => (
    <div>
      <div>{count}</div>
      <button
        class="p-2 text-green-500"
        on={dom.click((event, signal) => {
          count++;
          this.update();
        })}
      >
        Inc
      </button>
    </div>
  );
}

이 방식은 코드를 더 명령형(imperative)으로 만들고 기계적으로 단순하게 만듭니다.

이걸 하고, 그다음 저걸 하라는 식이죠.

‘뷰(view)는 상태(state)의 함수’라는 리액트의 약속 대신 전환(transition)을 택한 것입니다.

이벤트는 일급 객체이며 웹의 내장 이벤트 메커니즘을 사용하는데요.

‘onClick’ 대신 보편적인 ‘on’ 속성과 표준 DOM 이벤트 라이브러리가 있고, 개발자가 자신만의 커스텀 이벤트(CustomEvent)를 정의할 수도 있습니다.

비동기 작업을 제어하기 위해 Remix는 시그널(signal)에 의존합니다.

예를 들어 컴포넌트가 마운트 해제될 때 fetch를 취소하려면 개발자는 다음과 같이 작성할 수 있습니다.

function Cities(this: Remix.Handle) {
  let list = [], isLoading = true;
  fetch("https://api.remix.run/cities.json", {
    signal: this.signal // <- 여기를 주목하세요
  })
    .then(response => response.json())
    .then(data => {
      list = data;
      isLoading = false;
      this.update();
    });

  return () => 
}

Remix는 컴포넌트 라이브러리와 함께 출시될 예정인데요.

리액트에는 방대한 컴포넌트 생태계가 있지만 Remix에서는 작동하지 않기 때문에, 경쟁력을 갖추기 위해 팀에서 고품질의 내장 컴포넌트를 준비하고 있습니다.

세부 사항과 접근성 지원에 신경 쓴 메뉴나 폼(form) 같은 것들 말이죠.

또한 리액트에 비해 미묘하지만 좋은 삶의 질 향상 기능들도 도입했는데, 내장 css 속성이나 className 대신 class를 사용하는 것 등이 있습니다.

백엔드 측면에서 Remix는 웹 플랫폼에 더욱 집중합니다.

핸들러는 웹 ‘Request’를 받아 ‘Response’를 반환하거든요.

또한 ‘FormData’, ‘File’ 같은 것들을 서버로 가져옵니다.

이렇게 하면 서버 런타임은 구현 세부 사항이 되어버리죠.

Node, Deno, Bun 모두 이러한 웹 API에 대한 네이티브 지원이나 어댑터를 가지고 있으므로 Remix는 어디서든 실행될 수 있습니다.

v3에서 이 프레임워크는 파일 기반 라우팅을 포기했는데요.

지원하고자 하는 다양한 기능들을 파일 이름만으로 캡처하기에는 너무 골치 아픈 일이 많았기 때문입니다.

대신 TypeScript 기반의 라우트 정의 방식을 도입했습니다.

타입스크립트는 모든 라우트가 구현되었는지, URL 파라미터가 핸들러에 제대로 전달되는지 보장하며, 링크가 깨지는 일도 없게 해 주거든요.

let routes = route({
  home: "/",
  about: "/about",
  books: {
    index: { method: "GET", pattern: "/" },
    create: { method: "POST", pattern: "/" },
    show: "/books/:slug",
  },
});

// 서버에서의 구현
router.map(routes.books, booksHandlers)

// 클라이언트에서의 참조
<a href={routes.home.href()}></a>;

서버에는 로깅이나 파일 저장소 같은 건전한 기능들도 내장되어 있습니다.

가장 큰 차이는 클라이언트와 서버 사이에서 일어나는 일인데요.

Remix v3의 접근 방식은 RSC보다 훨씬 덜 마법처럼 느껴집니다.

커스텀 JSON 하이드레이션 스트림 같은 건 없거든요.

대신 Remix는 비동기 로딩 경계를 생성하여 iFrame을 재발명하고, HTMX 스타일로 HTML을 전송 포맷으로 사용합니다.

HTML과 자바스크립트를 결합하기 위해 웹 컴포넌트를 사용하는 힌트도 보입니다.

요약 및 전망

Remix는 웹 플랫폼과 타입스크립트에 계속 의존하면서, 풀스택의 더 넓은 영역을 제어하고 있습니다.

리액트의 미묘하고 복잡한 부분들을 단순한 this.update()로 버렸는데, 이는 코드를 덜 마법적으로 만들고 인간과 LLM 모두에게 이해하기 쉽게 만들어 주거든요.

Remix는 넥스트가 되었어야 할 모습의 ‘단순 무식하지만 효과적인(Grug Brain)’ 버전이라고 할 수 있습니다.

그럼 다음엔 무슨 일이 일어날까요?

해커 뉴스(Hacker News)의 까칠한 사람들은 또 다른 자바스크립트 프레임워크가 나왔다며 불평하겠죠.

당장 Remix를 배우고 모든 프로젝트를 이주해야 할 것처럼 보일 수도 있습니다.

하지만 그럴 필요는 전혀 없습니다.

리액트는 여전히 괜찮고(리액트를 선택했다고 해고당한 사람은 없으니까요), 좋은 부분만 계속 사용해도 됩니다(이게 자바스크립트의 흔한 방식이니까요).

Remix v3는 리액트 커뮤니티의 강력한 좌절감과 변화에 대한 갈망을 보여주는 신호탄입니다.

함수형에서 명령형으로 향하는 시계추가 이제 반대 방향으로 움직이기 시작한 것입니다.