본문으로 건너뛰기
김신건의 로그

[Frontend] React 19.x: Actions, Activity, RSC, Foundation

· 수정 · 📖 약 5분 · 1,794자/단어 #react #frontend #javascript #server-components #ssr
React 19, React 19.1, React 19.2, React Server Components, useActionState, useFormStatus, useOptimistic, useEffectEvent, Activity component, Partial Pre-rendering, React Foundation, ref as prop, Document Metadata, Asset Loading

정의

React 19 (2024-12-05) 는 Server Components 의 정식화Actions 라는 새 패러다임을 들고 나온 메이저 릴리즈. 이후 19.1 (2025-06), 19.2 (2025-10-01) 까지 minor 릴리즈에서 Activity / Performance Tracks / Partial Pre-rendering 같은 굵직한 기능 이 계속 추가되었다.

2026-06 시점 기준 현재 LTS 줄기는 19.x. React 20 / 19.3 은 아직 공식 발표 전. 이 페이지는 2026-06 의 운영자 시점 에서 정리한 React 19.x 의 작은 백과.

버전 매트릭스

버전출시핵심
19.02024-12-05Actions, ref-as-prop, Document Metadata, Asset Loading, use(), useActionState / useFormStatus / useOptimistic, Server Components 안정화
19.12025-06점진 안정화 + 버그 픽스 (큰 신 기능 없음)
19.22025-10-01<Activity>, useEffectEvent, cacheSignal, Performance Tracks, Partial Pre-rendering, Web Streams for Node, useId prefix _r_
19.0.1 / 19.1.2 / 19.2.12025-12-03RSC RCE 보안 패치

Actions: 폼/네트워크 워크플로의 새 표준

폼 제출 같은 비동기 전이useTransition 위에서 정식화 한 것이 Actions. 함수 자체에 async 가 들어가도 isPending 이 자동으로 잡힌다.

function UpdateName() {
  const [name, setName] = useState('');
  const [error, setError] = useState(null);
  const [isPending, startTransition] = useTransition();

  const handleSubmit = () => {
    startTransition(async () => {
      const err = await updateName(name);
      if (err) {
        setError(err);
        return;
      }
      redirect('/path');
    });
  };

  return (
    <div>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <button onClick={handleSubmit} disabled={isPending}>Update</button>
      {error && <p>{error}</p>}
    </div>
  );
}

위 패턴 위에 3 종 hook 이 얹힌다:

Hook역할
useActionState(action, initial)Action 의 마지막 결과 + isPending 보관. 폼 결과 처리의 표준
useFormStatus()<form>자손 컴포넌트 에서 부모 폼의 pending 상태 조회 (prop drilling 없이)
useOptimistic(state, updater)낙관적 업데이트 (서버 응답 전 미리 UI 갱신)

<form action={fn}> 형태로 DOM 액션 prop 도 추가. Server Actions ('use server') 와 합쳐지면 클라이언트 → 서버 mutation 의 일등 시민이 된다.

Server Components 정식화

'use client' / 'use server' 디렉티브 기반의 분할. 19 에서 안정 API 로 진입.

디렉티브의미
'use client'번들러에게 클라이언트 경계 알림. 별도 <script> 청크로 묶임
'use server'번들러에게 서버 endpoint 알림. 클라이언트에서 호출하면 POST 가 일어남

번들러 기능 이지 React 의 런타임 기능이 아니다. Next.js, Waku, RedwoodJS 같은 프레임워크 가 묶어서 제공.

ref 가 prop 이 되다

forwardRef 는 더 이상 필요 없다. 함수 컴포넌트가 그냥 ref prop 을 받을 수 있다.

// 19 이전
const Button = forwardRef(function Button(props, ref) {
  return <button ref={ref} {...props} />;
});

// 19+
function Button({ ref, ...props }) {
  return <button ref={ref} {...props} />;
}

forwardRef 자체는 deprecated. 새 코드는 바로 prop 으로 받자.

Document Metadata

<title>, <meta>, <link>컴포넌트 트리 어디에서나 렌더 가능. React 가 자동으로 <head> 로 올린다. React Helmet 같은 라이브러리가 사실상 불필요.

function BlogPost({ post }) {
  return (
    <article>
      <h1>{post.title}</h1>
      <title>{post.title}</title>
      <meta name="author" content="Josh" />
      <link rel="author" href="https://twitter.com/joshcstory/" />
      <meta name="keywords" content={post.keywords} />
    </article>
  );
}

SSR / RSC / CSR 어디서나 같은 방식. 중복 태그는 React 가 알아서 dedupe.

Asset Loading 과 preload / preinit

스타일시트, 스크립트, 폰트, 이미지의 로딩 라이프사이클 을 Suspense 와 연결. 데이터처럼 준비될 때까지 일관되게 기다림.

import { preload, preinit } from 'react-dom';

// 곧 쓸 자원을 미리 로드 (priority hint)
preload('https://example.com/font.woff2', { as: 'font' });

// 다운로드 + 초기화까지
preinit('https://example.com/script.js', { as: 'script' });

라우터 / 코드 스플리트 시점에 미리 호출해두면 TTI 개선.

use() API: Promise / Context 의 일관된 read

use(promise)렌더 중 Promise 결과 를 읽는다. Suspense 가 받아서 fallback 을 띄운다.

use(context)useContext 와 거의 같지만 if 안에서 호출 가능. Rules of Hooks 의 최상위 호출 제약을 조건부 사용 영역에서 풀어준 첫 hook.

function Message({ messagePromise }) {
  const msg = use(messagePromise); // Suspense 가 받음
  return <p>{msg}</p>;
}

19.2 의 큰 4가지

1. <Activity>: pre-render + 상태 보존

// 이전
{isVisible && <Page />}

// 19.2+
<Activity mode={isVisible ? 'visible' : 'hidden'}>
  <Page />
</Activity>
mode효과
visible정상 렌더 + effect mount
hidden렌더는 유지 하되 effect 는 unmount, 업데이트는 우선순위 낮춤

다음 페이지로 갈 가능성이 높은 영역을 백그라운드로 미리 그려두기. 뒤로가기 시 입력값/스크롤 등 상태 보존. SPA 라우터의 워킹 디스플레이 패턴.

2. useEffectEvent

useEffect의존성으로 들어가야 하는 값그 안에서 단순히 읽기만 하는 값문법적으로 분리. eslint-plugin-react-hooks@latest 가 디펜던시 배열에 자동으로 넣지 않도록 처리한다.

function ChatRoom({ roomId, theme }) {
  // theme 가 바뀌어도 effect 는 재실행 안 됨
  const onConnected = useEffectEvent(() => {
    showNotification('Connected!', theme);
  });

  useEffect(() => {
    const conn = createConnection(serverUrl, roomId);
    conn.on('connected', () => onConnected());
    conn.connect();
    return () => conn.disconnect();
  }, [roomId]); // theme 는 의존성이 *아니다*
}

“이건 이벤트인데 effect 안에서 발생한다” 라는 드문 사례 만 사용. 모든 함수를 wrap 하는 남발 금지.

3. Performance Tracks (Chrome DevTools)

Chrome DevTools 의 custom track 으로 React 의 Scheduler / Components 두 트랙 추가.

  • Scheduler ⚛: blocking / transition / idle 우선순위별 작업 흐름.
  • Components ⚛: 컴포넌트 트리의 mount / render / effect 시점.

기존 React DevTools Profiler 보다 브라우저 전체 timing 과 함께 볼 수 있어서 interaction → first paint 까지 일관된 그림. reference/dev-tools/react-performance-tracks 참고.

4. Partial Pre-rendering

정적 부분은 미리 빌드해 CDN 에서, 동적 부분은 런타임에 이어서 렌더.

// 빌드 시
const { prelude, postponed } = await prerender(<App />, {
  signal: controller.signal,
});
await savePostponedState(postponed);
// prelude 를 CDN 으로

// 런타임
const postponed = await getPostponedState(request);
const resumeStream = await resume(<App />, postponed);
// 클라이언트로 스트림

Next.js / Vercel 의 Partial Pre-rendering (PPR) 이 같은 의도. React 가 직접 지원 하게 됨.

사라지는 것들

항목상태
forwardRefdeprecated. ref prop 사용
defaultProps (함수 컴포넌트)제거
String refs (<X ref="foo">)제거
Module Pattern Factories제거
createFactory제거
react-test-renderer/shallow제거 (Enzyme 종료 흐름)
Create React App2025-02-14 sunsetting

CRA 는 공식 종료. 새 프로젝트는 Vite, Next.js, Parcel, RSBuild, Expo 중 선택. 프레임워크 없이 시작 도 공식 가이드가 있다.

보안: 2025-12 RSC 사건

날짜사건
2025-12-03RSC 의 unauthenticated RCE 공개. 19.0.1 / 19.1.2 / 19.2.1 으로 즉시 업그레이드 권장
2025-12-11동일 패치 시도 중 추가 취약점 2건 (DoS, Source Code Exposure) 발견

Server Components 를 프로덕션 에서 쓰는 모든 곳 이 영향. RSC 위에 입력 검증 / 권한 체크 가 반드시 들어가야 한다는 점이 다시 부각되었다.

React Foundation

날짜사건
2025-10-07React Foundation 발표. Meta 단독 에서 재단 거버넌스
2026-02-24Linux Foundation 산하 정식 출범. AWS, Amazon, Callstack, Expo, Microsoft, Software Mansion, Vercel 합류

Meta 의 내부 release process외부 stakeholder공동 운영 으로 전환. Vue 와 비슷한 재단 거버넌스 모델.

React 17/18 에서 19 로

19 Upgrade Guide 의 골자:

  1. 모든 변경 이 codemod 로 자동화되어 있다 (@codemod/react-19-codemod 류).
  2. Suspense 안의 사이드 이펙트 가 더 엄격해짐. useEffect 의 클린업 누락 등이 새로 잡힘.
  3. Strict Mode 가 더 강력해짐 (double-invoke 가 effect 까지 확장).
  4. peer dep 으로 react@18 을 요구하는 라이브러리들이 대부분 19 호환 되었다. 안 된 곳만 알림.

김신건의 현장 메모

  • Asset Loading 은 SSR 페이지에서 FOUC 줄이는 효과가 즉시 보인다. 라우트 진입 직전 preinit('app.css', { as: 'style' }) 한 줄.
  • Actions<form action={...}> 형태로 progressive enhancement 가 그대로 가능. JS off 인 환경에서도 폼이 동작하는 것이 오랜만에 부활한 정통.
  • Activity탭 전환이 많은 admin 같은 곳에서 강력. 상태 보존 이 직접 코드보다 깔끔.
  • Performance Tracks언제 effect 가 늦게 mount 되었는지 가 Chrome 화면 안에서 그대로 보여서 문제 재현 의 grep 가능 영역이 커졌다.

관련 위키

참고

이 글의 용어 (4개)
[DevOps] 무중단 배포: Blue-Green, Canary, Rolling, Expand-Contractdevops
정의 무중단 배포 (Zero-Downtime Deployment) 는 서비스 가동을 멈추지 않고 새 버전을 배포하는 일련의 전략. 핵심 도전 4가지: 1. 트래픽 전환: 어떻게 …
[Frontend] React Compiler 1.0: 자동 memoization 의 새 표준frameworks
정의 React Compiler 는 React 컴포넌트와 hook 의 불필요한 재계산 을 빌드 타임에 자동으로 잡아주는 optimizing compiler. 손으로 / / 를 박…
[Frontend] SPA Architecture: CSR, SSR, SSG, hydrationjavascript
정의 SPA (Single Page Application) 는 첫 로딩 시 받은 HTML / JS 번들 하나로 모든 화면 전환을 클라이언트에서 처리하는 웹 앱 구조. URL 변경…
[Javascript] async/awaitjavascript
정의 / 는 기반 비동기 코드를 마치 동기 코드처럼 쓸 수 있게 해주는 ES2017 의 문법 설탕. 본질은 Promise 그 자체, 문법만 다르다. 전체 동작 메커니즘은 글 참조…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기