NAVIGATION
  • 전체 글
CATEGORIES
  • Develop7
    • Backend3
    • Frontend2
    • Git1
    • Performance1
  • AI3
    • Claude Code3
  • Frontend1
    • Next.js1
POPULAR TAGS
  • API3
  • 클로드코드2
  • 성능최적화2
  • GraphQL2
  • REST2
  • React2
  • JavaScript2
  • 프론트엔드2
  • Claude Code1
  • AI1
···
>steady-one_

© 2025 steady-one Blog. All rights reserved.

React 19의 새로운 기능 총정리
Frontend
2025년 10월 1일

React 19의 새로운 기능 총정리

React 19에서 새롭게 추가된 주요 기능들을 실용적인 예제와 함께 상세히 알아봅니다.

.react.javascript.프론트엔드

React 19의 새로운 기능 총정리

React 19가 공식 출시되면서 프론트엔드 개발 생태계에 큰 변화를 가져왔습니다. 이번 버전은 단순한 마이너 업데이트가 아닌, 개발자 경험과 성능을 대폭 향상시키는 혁신적인 기능들을 담고 있습니다. 이 글에서는 React 19의 주요 신기능들을 실용적인 코드 예제와 함께 자세히 살펴보겠습니다.

1. React Compiler: 자동 최적화의 시대

React 19의 가장 혁명적인 변화는 바로 React Compiler의 도입입니다. 이전까지 개발자들은 useMemo, useCallback, React.memo 등을 수동으로 사용하여 성능을 최적화해야 했습니다. React Compiler는 이러한 최적화를 자동으로 수행하여 개발자의 부담을 크게 줄여줍니다.

이전 방식 vs React 19

// React 18: 수동 최적화 필요
function TodoList({ todos, filter }) {
  const filteredTodos = useMemo(() => {
    return todos.filter(todo => todo.status === filter);
  }, [todos, filter]);
 
  const handleClick = useCallback((id) => {
    console.log('Clicked:', id);
  }, []);
 
  return (
    <ul>
      {filteredTodos.map(todo => (
        <TodoItem key={todo.id} todo={todo} onClick={handleClick} />
      ))}
    </ul>
  );
}
 
// React 19: 자동 최적화
function TodoList({ todos, filter }) {
  // Compiler가 자동으로 메모이제이션 처리
  const filteredTodos = todos.filter(todo => todo.status === filter);
 
  const handleClick = (id) => {
    console.log('Clicked:', id);
  };
 
  return (
    <ul>
      {filteredTodos.map(todo => (
        <TodoItem key={todo.id} todo={todo} onClick={handleClick} />
      ))}
    </ul>
  );
}

React Compiler는 코드를 분석하여 불필요한 리렌더링을 자동으로 방지합니다. 이는 코드의 가독성을 높이고 버그 가능성을 줄이면서도 최적의 성능을 유지할 수 있게 해줍니다.

2. Actions: 비동기 작업의 새로운 패러다임

React 19는 Actions라는 새로운 개념을 도입하여 비동기 작업 처리를 더욱 간편하게 만들었습니다. useTransition과 useActionState 훅을 통해 폼 제출, 데이터 페칭 등의 비동기 작업을 선언적으로 처리할 수 있습니다.

useActionState를 활용한 폼 처리

'use client';
 
import { useActionState } from 'react';
 
async function submitForm(prevState, formData) {
  const name = formData.get('name');
  const email = formData.get('email');
 
  try {
    const response = await fetch('/api/subscribe', {
      method: 'POST',
      body: JSON.stringify({ name, email }),
    });
 
    if (!response.ok) throw new Error('구독 실패');
 
    return {
      success: true,
      message: '구독이 완료되었습니다!',
    };
  } catch (error) {
    return {
      success: false,
      message: error.message,
    };
  }
}
 
function Newsletter() {
  const [state, formAction, isPending] = useActionState(submitForm, {
    success: null,
    message: '',
  });
 
  return (
    <form action={formAction}>
      <input type="text" name="name" placeholder="이름" required />
      <input type="email" name="email" placeholder="이메일" required />
 
      <button type="submit" disabled={isPending}>
        {isPending ? '구독 중...' : '구독하기'}
      </button>
 
      {state.message && (
        <p className={state.success ? 'success' : 'error'}>
          {state.message}
        </p>
      )}
    </form>
  );
}

이 패턴은 로딩 상태, 에러 처리, 성공 메시지를 자동으로 관리하므로 별도의 상태 관리 코드가 필요 없습니다.

3. useOptimistic: 낙관적 업데이트의 표준화

사용자 경험을 개선하기 위한 **낙관적 업데이트(Optimistic Update)**가 React 19에서 공식 훅으로 제공됩니다. useOptimistic 훅을 사용하면 서버 응답을 기다리지 않고 UI를 즉시 업데이트할 수 있습니다.

'use client';
 
import { useOptimistic } from 'react';
import { addTodo } from './actions';
 
function TodoApp({ todos }) {
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo) => [...state, { ...newTodo, pending: true }]
  );
 
  async function handleSubmit(formData) {
    const title = formData.get('title');
 
    // 즉시 UI 업데이트
    addOptimisticTodo({ id: Date.now(), title, completed: false });
 
    // 실제 서버 요청
    await addTodo(title);
  }
 
  return (
    <div>
      <form action={handleSubmit}>
        <input name="title" placeholder="새 할 일" />
        <button type="submit">추가</button>
      </form>
 
      <ul>
        {optimisticTodos.map(todo => (
          <li key={todo.id} style={{ opacity: todo.pending ? 0.5 : 1 }}>
            {todo.title}
            {todo.pending && <span> (저장 중...)</span>}
          </li>
        ))}
      </ul>
    </div>
  );
}

이 접근 방식은 특히 네트워크가 느린 환경에서 사용자가 앱이 빠르게 반응한다고 느끼게 만듭니다.

4. use() Hook: 비동기 데이터의 혁신

React 19는 use() 훅을 도입하여 Promise와 Context를 더욱 자연스럽게 다룰 수 있게 했습니다. 이는 조건부로 훅을 호출할 수 있다는 점에서 기존 훅들과 차별화됩니다.

Promise와 함께 사용하기

import { use, Suspense } from 'react';
 
async function fetchUserData(userId) {
  const response = await fetch(`/api/users/${userId}`);
  return response.json();
}
 
function UserProfile({ userPromise }) {
  // Promise를 직접 use()로 unwrap
  const user = use(userPromise);
 
  return (
    <div>
      <h2>{user.name}</h2>
      <p>{user.email}</p>
      <p>가입일: {user.joinedAt}</p>
    </div>
  );
}
 
function UserPage({ userId }) {
  const userPromise = fetchUserData(userId);
 
  return (
    <Suspense fallback={<div>로딩 중...</div>}>
      <UserProfile userPromise={userPromise} />
    </Suspense>
  );
}

조건부 Context 읽기

import { use, createContext } from 'react';
 
const ThemeContext = createContext(null);
 
function Button({ primary }) {
  // 조건부로 Context 사용 가능!
  const theme = primary ? use(ThemeContext) : null;
 
  return (
    <button style={{
      backgroundColor: primary ? theme.primaryColor : 'gray'
    }}>
      클릭하세요
    </button>
  );
}

기존 React 규칙에서는 훅을 조건문 안에서 호출할 수 없었지만, use()는 이러한 제약에서 자유롭습니다.

5. Server Components와 Server Actions의 개선

React 19는 Server Components와 Server Actions의 통합을 더욱 강화했습니다. 이제 클라이언트와 서버 간의 경계가 더욱 명확하고 사용하기 쉬워졌습니다.

Server Actions 예제

// app/actions.ts
'use server';
 
import { revalidatePath } from 'next/cache';
import { db } from '@/lib/db';
 
export async function createPost(formData: FormData) {
  const title = formData.get('title') as string;
  const content = formData.get('content') as string;
 
  // 서버에서만 실행되는 코드
  const post = await db.post.create({
    data: { title, content, published: true },
  });
 
  // 캐시 무효화
  revalidatePath('/posts');
 
  return { success: true, postId: post.id };
}
 
// app/components/PostForm.tsx
'use client';
 
import { createPost } from '@/app/actions';
import { useActionState } from 'react';
 
export function PostForm() {
  const [state, formAction, isPending] = useActionState(createPost, null);
 
  return (
    <form action={formAction}>
      <input name="title" placeholder="제목" required />
      <textarea name="content" placeholder="내용" required />
      <button type="submit" disabled={isPending}>
        {isPending ? '발행 중...' : '발행하기'}
      </button>
      {state?.success && <p>포스트가 발행되었습니다!</p>}
    </form>
  );
}

이 패턴은 API 라우트를 별도로 만들 필요 없이 폼 제출을 직접 서버 함수로 연결합니다.

6. Document Metadata의 네이티브 지원

이제 컴포넌트 내에서 직접 <title>, <meta>, <link> 태그를 사용할 수 있습니다. React 19는 이를 자동으로 document head로 호이스팅합니다.

function BlogPost({ post }) {
  return (
    <article>
      {/* 자동으로 <head>로 이동 */}
      <title>{post.title} - 내 블로그</title>
      <meta name="description" content={post.excerpt} />
      <meta property="og:title" content={post.title} />
      <meta property="og:image" content={post.coverImage} />
      <link rel="canonical" href={`https://myblog.com/posts/${post.slug}`} />
 
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}

이는 Next.js의 next/head나 Remix의 meta export와 유사하지만, React 코어 레벨에서 지원된다는 점이 중요합니다.

7. ref를 prop으로 사용

더 이상 forwardRef가 필요 없습니다! React 19에서는 함수 컴포넌트가 ref를 일반 prop으로 받을 수 있습니다.

// React 18: forwardRef 필요
import { forwardRef } from 'react';
 
const Input = forwardRef(function Input(props, ref) {
  return <input ref={ref} {...props} />;
});
 
// React 19: 일반 prop으로 사용
function Input({ ref, ...props }) {
  return <input ref={ref} {...props} />;
}
 
// 사용
function Form() {
  const inputRef = useRef(null);
 
  const handleSubmit = () => {
    inputRef.current.focus();
  };
 
  return (
    <>
      <Input ref={inputRef} placeholder="이름을 입력하세요" />
      <button onClick={handleSubmit}>제출</button>
    </>
  );
}

이는 코드를 더 간결하게 만들고 TypeScript 타입 추론도 개선합니다.

8. 향상된 Hydration 에러 처리

React 19는 hydration 불일치 오류 메시지를 크게 개선했습니다. 이제 정확히 어디서 불일치가 발생했는지 알려주며, 해결 방법까지 제안합니다.

// Hydration 불일치 예제
function TimeDisplay() {
  // 서버: 빌드 타임의 시간
  // 클라이언트: 현재 시간 → 불일치!
  return <div>현재 시간: {new Date().toLocaleTimeString()}</div>;
}
 
// 올바른 방법
'use client';
 
function TimeDisplay() {
  const [mounted, setMounted] = useState(false);
 
  useEffect(() => {
    setMounted(true);
  }, []);
 
  if (!mounted) {
    return <div>현재 시간: --:--:--</div>;
  }
 
  return <div>현재 시간: {new Date().toLocaleTimeString()}</div>;
}

React 19는 이러한 패턴을 자동으로 감지하고 개발자 도구에서 명확한 경고를 제공합니다.

9. 개선된 Context 성능

Context API의 성능이 대폭 개선되어 이제 대규모 애플리케이션에서도 안심하고 사용할 수 있습니다.

import { createContext, use } from 'react';
 
const UserContext = createContext(null);
 
function UserProvider({ children }) {
  const [user, setUser] = useState(null);
 
  // React 19의 자동 최적화로 인해
  // value 객체를 useMemo로 감쌀 필요 없음
  return (
    <UserContext.Provider value={{ user, setUser }}>
      {children}
    </UserContext.Provider>
  );
}
 
// 여러 컴포넌트가 동일한 Context를 구독해도
// 필요한 부분만 리렌더링
function UserName() {
  const { user } = use(UserContext);
  return <span>{user?.name}</span>;
}
 
function UserEmail() {
  const { user } = use(UserContext);
  return <span>{user?.email}</span>;
}

결론

React 19는 단순한 버전 업그레이드를 넘어 프론트엔드 개발 패러다임의 진화를 보여줍니다. React Compiler를 통한 자동 최적화, Actions를 통한 비동기 처리 개선, 그리고 Server Components와의 긴밀한 통합은 개발자 경험과 애플리케이션 성능을 동시에 향상시킵니다.

특히 주목할 점은 **"최적화를 잊어라"**라는 새로운 철학입니다. 이전에는 성능을 위해 개발자가 신경 써야 할 부분이 많았지만, React 19는 이러한 부담을 크게 줄여줍니다. 이제 개발자는 비즈니스 로직에 더 집중할 수 있습니다.

마이그레이션 시 고려사항

React 19로 업그레이드할 때 다음 사항들을 확인하세요:

  1. React Compiler 활성화: babel-plugin-react-compiler 설정
  2. forwardRef 제거: 일반 props로 변경
  3. useTransition과 Actions 도입: 기존 비동기 로직 개선
  4. Server Components 활용: Next.js 14+ 환경에서 최적화

React 19는 아직 초기 단계이지만, 이미 프로덕션에서 사용할 수 있을 만큼 안정적입니다. Meta의 수천 개 컴포넌트에서 이미 검증되었으며, 커뮤니티의 피드백을 통해 지속적으로 개선되고 있습니다.

앞으로의 React 생태계가 더욱 기대되는 시점입니다. 여러분의 프로젝트에도 React 19의 새로운 기능들을 적용해보시길 권장합니다!


참고 자료:

  • React 19 공식 문서
  • React Compiler 소개
  • Server Actions 가이드

목차

  • React 19의 새로운 기능 총정리
  • 1. React Compiler: 자동 최적화의 시대
  • 2. Actions: 비동기 작업의 새로운 패러다임
  • 3. useOptimistic: 낙관적 업데이트의 표준화
  • 4. use() Hook: 비동기 데이터의 혁신
  • 5. Server Components와 Server Actions의 개선
  • 6. Document Metadata의 네이티브 지원
  • 7. ref를 prop으로 사용
  • 8. 향상된 Hydration 에러 처리
  • 9. 개선된 Context 성능
  • 결론