header-img
Info :
  1. React 19의 새로운 기능
    1. Action
    2. React Server Component
  2. React 19의 개선 사항
728x90

 

 

React 19 Beta – React

The library for web and native user interfaces

react.dev

 

일부 해석 발췌

 

React 19의 새로운 기능

Action

리액트 앱의 일반적인 사용 사례는 데이터 변화를 수행한 다음 응답으로 상태를 업데이트하는 것입니다. 예를 들어, 사용자가 이름을 변경하기 위해 양식을 제출하면 API 요청을 한 다음 응답을 처리합니다. 과거에는 보류 상태, 오류, 낙관적 업데이트 및 순차적 요청을 수동으로 처리해야 했습니다.

 

예를 들어 usestate에서 보류 및 오류 상태를 처리할 수 있습니다.

// Before Actions
function UpdateName({}) {
  const [name, setName] = useState("");
  const [error, setError] = useState(null);
  const [isPending, setIsPending] = useState(false);

  const handleSubmit = async () => {
    setIsPending(true);
    const error = await updateName(name);
    setIsPending(false);
    if (error) {
      setError(error);
      return;
    } 
    redirect("/path");
  };

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

 

React 19 에서는 보류 중인 상태, 오류, 양식 및 낙관적 업데이트를 자동으로 처리하기 위해 전환에 Async functions을 사용하는 지원을 추가하고 있습니다.

 

예를 들어, 'useTransition'을 사용하여 보류 상태를 처리할 수 있습니다.

// Using pending state from Actions
function UpdateName({}) {
  const [name, setName] = useState("");
  const [error, setError] = useState(null);
  const [isPending, startTransition] = useTransition();

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

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

 

비동기 전환은 즉시 isPending 상태를 True로 설정하고, 비동기 요청을 하고, isPending 전환 후에는 false로 전환합니다. 이를 통해 데이터가 변경되는 동안 현재 UI의 반응성과 대화형을 유지할 수 있습니다.

 

관례적으로 비동기 전환을 사용하는 함수를 'Action'이라고 한다.

Action은 제출된 데이터를 자동으로 관리.
- Pending State: 작업은 요청 시작 시 시작되고 최종 상태 업데이트가 커밋되면 자동으로 재설정되는 보류 상태를 제공
- Optimistic Updates: 작업은 새로운 useOptimistic 훅을 지원하므로 요청이 제출되는 동안 사용자에게 즉각적인 피드백을 표시할 수 있음
- Error handling: 작업은 오류 처리를 제공하므로 요청이 실패할 때 오류 경계를 표시하고, 낙관적 업데이트를 원래 값으로 자동으로 되돌릴 수 있음.
- Forms: <form> 요소는 이제 Action 및 formAction 소품에 함수 전달을 지원함. props에 함수를 전달하면 action 기본적으로 Actions가 사용되며 제출 후 자동으로 양식이 재설정됨.

 

Actions를 기반으로 React 19에서는 useOptimistic 과 Actions의 일반적인 사례를 처리하는 새로운 훅인 React.useActionState를 도입합니다. React-dom에서는 양식을 자동으로 관리하는 Actions와 양식의 일반적인 사례를 지원하는 useFormStatus를 추가하고 있습니다.

 

React 19 에서 위의 예는 다음과 같이 단순화할 수 있습니다.

// Using <form> Actions and useActionState
function ChangeName({ name, setName }) {
  const [error, submitAction, isPending] = useActionState(
    async (previousState, formData) => {
      const error = await updateName(formData.get("name"));
      if (error) {
        return error;
      }
      redirect("/path");
    }
  );

  return (
    <form action={submitAction}>
      <input type="text" name="name" />
      <button type="submit" disabled={isPending}>Update</button>
      {error && <p>{error}</p>}
    </form>
  );
}

 

 

New Hook: useActionState

일반적인 사례를 쉽게 사용할 수 있도록 useActionState 라는 새로운 훅을 추가했습니다.

const [error, submitAction, isPending] = useActionState(async (previousState, newName) => {
  const error = await updateName(newName);
  if (error) {
    // You can return any result of the action.
    // Here, we return only the error.
    return error;
  }
  
  // handle success
});

 

useActionState Function("Action")를 Pending하고 호출할 Action을 반환합니다. 이것은 액션이 구성되기 때문에 작동합니다. 래핑된 액션이 호출되면 useActionState는 액션의 마지막 결과를 데이터로, 보류 중인 액션의 상태를 Pending으로 반환합니다.

 

이전의 카나리아 릴리즈에서 React.useActionState를 ReactDOM.useFormState라고 불렀지만
FormState라는 이름을 변경하고, useFormState를 사용하지 않도록 변경했다.
 

Add `React.useActionState` by rickhanlonii · Pull Request #28491 · facebook/react

Overview Depends on #28514 This PR adds a new React hook called useActionState to replace and improve the ReactDOM useFormState hook. Motivation This hook intends to fix some of the confusion and l...

github.com

 

React Dom: <form> Actions

Action은 React-DOM을 위한 React 19의 새로운 <form> 기능과도 통합되어 있습니다. Action과 함께 자동으로 양식을 제출할 수 있도록 <form>, <input>, <button> 요소의 Action과 formAction Props로 통과 기능 지원을 추가했습니다.

<form action={actionFunction}>

 

<form> Action이 성공하면 React는 제어되지 않는 구성 요소에 대해 자동으로 양식을 재설정합니다. <form>을 수동으로 재설정해야 하는 경우, 새로운 requestFormResetReactDOM API를 호출할 수 있습니다.

 

React DOM: New Hook: useFormStatus

설계 시스템에서는 구성 요소에 추가하지 않고 <form>에 대한 정보에 엑세스해야 하는 설계 구성 요소를 작성하는 것이 일반적입니다. 이 작업은 Context를 통해 수행할 수 있지만, 일반적인 경우를 더 쉽게 만들기 위해 다음과 같은 새 훅인 useFormStatus를 추가했습니다. 

import {useFormStatus} from 'react-dom';

function DesignButton() {
  const {pending} = useFormStatus();
  return <button type="submit" disabled={pending} />
}

 

useFormStatus는 양식이 컨텍스트 공급자인 것처럼 부모 <form>의 상태를 읽습니다.

 

New Hook: useOptimistic

데이터 변환을 수행할 때 또 다른 일반적인 UI 패턴은 비동기 요청이 진행되는 동안 최종 상태를 낙관적으로 보여주는 것. React 19 에서는 이를 쉽게 하기 위해 useOptimistic 라는 새로운 Hook을 추가하고 있습니다.

function ChangeName({currentName, onUpdateName}) {
  const [optimisticName, setOptimisticName] = useOptimistic(currentName);

  const submitAction = async formData => {
    const newName = formData.get("name");
    setOptimisticName(newName);
    const updatedName = await updateName(newName);
    onUpdateName(updatedName);
  };

  return (
    <form action={submitAction}>
      <p>Your name is: {optimisticName}</p>
      <p>
        <label>Change Name:</label>
        <input
          type="text"
          name="name"
          disabled={currentName !== optimisticName}
        />
      </p>
    </form>
  );
}

 

updateName 요청이 진행되는 동안 useOptimistic Hook을 사용하면 OptimisticName이 즉시 렌더링됩니다. 업데이트가 완료되거나 오류가 발생하면 React는 자동으로 CurrentName 값으로 다시 전환됩니다.

 

New API: Use

Render로 리소스를 읽을 수 있는 새로운 API인 use.

 

예를 들어, use와 약속을 읽을 수 있으며, 약속이 해결될 때까지 반응이 일시 중단됩니다.

import {use} from 'react';

function Comments({commentsPromise}) {
  // `use` will suspend until the promise resolves.
  const comments = use(commentsPromise);
  return comments.map(comment => <p key={comment.id}>{comment}</p>);
}

function Page({commentsPromise}) {
  // When `use` suspends in Comments,
  // this Suspense boundary will be shown.
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Comments commentsPromise={commentsPromise} />
    </Suspense>
  )
}

 

use는 렌더로 작성된 약속을 지원하지 않습니다.

사용할 렌더에서 만든 약속을 전달하려고 하면 React는 다음과 같이 경고 합니다.

null

 

수정하려면 promises에 대한 캐싱을 지원하는 서스펜스 기반 라이브러리 또는 프레임워크에서 promise를 전달해야 합니다. 향후에는 렌더링에서 promises를 더 쉽게 캐시할 수 있도록 기능을 전달할 계획입니다.

 

또한 컨텍스트를 사용하여 읽을 수 있으므로 조기 반환 후와 같은 조건부 컨텍스트를 읽을 수 있습니다.

import {use} from 'react';
import ThemeContext from './ThemeContext'

function Heading({children}) {
  if (children == null) {
    return null;
  }
  
  // This would not work with useContext
  // because of the early return.
  const theme = use(ThemeContext);
  return (
    <h1 style={{color: theme.color}}>
      {children}
    </h1>
  );
}

 

use API 는 Hook과 마찬가지로 렌더에서만 호출할 수 있습니다. Hook과 달리 Use는 조건부로 호출할 수 있습니다. 앞으로 우리는 렌더에서 리소스를 사용하여 소비하는 더 많은 방법을 지원할 계획입니다.

 

React Server Component

(생략)

 

React 19의 개선 사항

Ref as a Prop

Ref를 Function Component의 prop 로 사용할 수 있습니다.

function MyInput({placeholder, ref}) {
  return <input placeholder={placeholder} ref={ref} />
}

//...
<MyInput ref={ref} />

 

새로운 기능 구성 요소는 더 이상 forwardRef가 필요하지 않으며, 새로운 참조 prop을 사용하기 위해 구성 요소를 자동으로 업데이트하는 코드 모드를 게시할 것 입니다. 향후 버전에서는 forwardRef를 사용하지 않고 제거할 것 입니다.

클래스에 전달된 refs는 구성 요소 인스턴스를 참조하므로 prop으로 전달되지 않습니다.

 

<Context> as a provider

React 19 에서는 <Context.Provider> 대신 <Context>를 공급자로 렌더링 할 수 있습니다.

const ThemeContext = createContext('');

function App({children}) {
  return (
    <ThemeContext value="dark">
      {children}
    </ThemeContext>
  );  
}

 

새 Context 제공자는 <Context>를 사용할 수 있으며, 기존 제공자를 변환하는 코드 모드를 게시할 예정입니다. 향후 버전에서는 <Context.Provider>를 사용하지 않습니다.

 

Cleanup functions for refs

이제 ref callback 에서 정리 기능을 반환할 수 있습니다.

<input
  ref={(ref) => {
    // ref created

    // NEW: return a cleanup function to reset
    // the ref when element is removed from DOM.
    return () => {
      // ref cleanup
    };
  }}
/>

 

구성 요소가 마운트 해제 되면 React는 Ref 콜백에서 반환되는 정리 함수를 호출한다. 이는 DOM Ref, class, Component Ref, useImperativeHandle에 대해 작동합니다.

이전에 React는 구성 요소를 마운트 해제할 때 null로 Ref 함수를 호출했습니다. Ref가 CleanUp 함수를 반환하면 React는 이제 이 단계를 건너뜁니다.
향후 버전에서는 구성 요소를 마운트 해제할 때 null로 참조를 호출하는 것을 금지합니다.

 

useDefferedValue initial value

useDefferedValue에 Initial Value 옵션을 추가했습니다.

(useDefferedValue 는 값의 업데이트 우선 순위를 지정하는 Hook)

function Search({deferredValue}) {
  // On initial render the value is ''.
  // Then a re-render is scheduled with the deferredValue.
  const value = useDeferredValue(deferredValue, '');
  
  return (
    <Results query={value} />
  );
}

 

initialValue가 제공되면 useDefferredValue 는 구성 요소의 초기 렌더에 대한 값으로 반환하고 deferrefValue re-render로 백그라운드에서 re-render을 예약합니다.

 

useDeferredValue – React

The library for web and native user interfaces

react.dev

 

Support for Document Metadata

React 19 에서는 기본적으로 다음과 같은 구성 요소에서 문서 메타데이터 태그를 렌더링하는 지원을 추가하고 있습니다.

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} />
      <p>
        Eee equals em-see-squared...
      </p>
    </article>
  );
}

 

리액트가 이 구성 요소를 렌더링하면 <title>, <link>, <meta> 태그가 표시되고 자동으로 문서의 <head> 섹션으로 호이스트됩니다. 이러한 메타데이터 태그를 기본적으로 지원함으로써 클라리언트 전용 앱, 스트리밍 SSR 및 서버 구성 요소와 함께 작동할 수 있도록 할 수 있습니다.

 

Support for StyleSheets

스타일시트는 외부링크(<link rel='stylesheet' href="....">)와 인라인(<style>...</style>) 모두 스타일 우선 순위 규칙으로 인해 DOM에서 신중한 위치 지정이 필요합니다. 구성 요소 내에서 합성을 허용하는 스타일시트 기능을 구축하는 것은 어렵기 때문에 사용자는 종종 자신에게 의존할 수 있는 구성 요소에서 멀리 떨어진 모든 스타일을 로드하거나 이 복잡성을 캡슐화하는 스타일 라이브러리를 사용합니다.

 

React 19에서는 이러한 복잡성을 해결하고 스타일시트를 지원하는 내장된 클라이언트의 동시 렌더링과 서버의 스트리밍 렌더링에 더욱 깊이 있는 통합을 제공하고 있습니다. React 19에 스타일시트의 우선순위를 알려주면 DOM에서 스타일시트의 삽입 순서를 관리하고 스타일시트가 로드되는지 확인한 후 해당 스타일 규칙에 따라 달라지는 내용을 공개합니다.

 

function ComponentOne() {
  return (
    <Suspense fallback="loading...">
      <link rel="stylesheet" href="foo" precedence="default" />
      <link rel="stylesheet" href="bar" precedence="high" />
      <article class="foo-class bar-class">
        {...}
      </article>
    </Suspense>
  )
}

function ComponentTwo() {
  return (
    <div>
      <p>{...}</p>
      <link rel="stylesheet" href="baz" precedence="default" />  <-- will be inserted between foo & bar
    </div>
  )
}

 

서버 사이드 렌더링 중에 React는 스타일 시트를 <head>에 포함시켜 브라우저가 로드될 때까지 그림을 그리지 않도록 합니다. 이미 스트리밍을 시작한 후 스타일 시트가 늦게 발견되면 React는 스타일 시트에 따라 달라지는 서스펜스 경계의 내용을 드러내기 전에 스타일시트가 클라이언트의 <head>에 삽입되도록 합니다.

 

클라이언트 측 렌더링 중에 React는 렌더링을 커밋하기 전에 새로 렌더링 된 스타일시트가 로드될 때까지 기다립니다. 응용 프로그램 내의 여러 장소에서 이 구성 요소를 렌더링하는 경우 React는 스타일시트를 문서에 한 번만 포함합니다.

function App() {
  return <>
    <ComponentOne />
    ...
    <ComponentOne /> // won't lead to a duplicate stylesheet link in the DOM
  </>
}

 

Support for Async scripts

HTML 일반 스크립트(<script src="...">)와 지연 스크립트(<script depar="" src="...">)는 문서 순서로 로드되므로 구성 요소 트리의 깊은 곳에 이러한 종류의 스크립트를 렌더링하기가 어렵습니다. 그러나 비동기 스크립트(<script async="" src="...">)는 임의의 순서로 로드됩니다.

 

React 19에서는 스크립트 인스턴스를 재배치 및 중복 제거하는 작업 없이 구성 요소 트리 내의 실제 스크립트에 의존하는 구성 요소 내부 어디에서나 렌더링할 수 있도록 함으로써 비동기 스크립트를 더 잘 지원할 수 있도록 했습니다.

function MyComponent() {
  return (
    <div>
      <script async={true} src="..." />
      Hello World
    </div>
  )
}

function App() {
  <html>
    <body>
      <MyComponent>
      ...
      <MyComponent> // won't lead to duplicate script in the DOM
    </body>
  </html>
}

 

 

Support for preloading resources

초기 문서 로드 및 클라이언트 측 업데이트 중에 브라우저에 가능한 한 빨리 로드해야 할 리소스에 대해 알려주면 페이지 성능에 극적인 영향을 미칠 수 있습니다.

 

React 19에는 비효율적인 리소스 로드로 인해 방해받지 않는 훌륭한 경험을 최대한 쉽게 구축할 수 있도록 브라우저 리소스를 로드하고 미리 로드하기 위한 여러 가지 새로운 API가 포함되어 있습니다.

 

import { prefetchDNS, preconnect, preload, preinit } from 'react-dom'
function MyComponent() {
  preinit('https://.../path/to/some/script.js', {as: 'script' }) // loads and executes this script eagerly
  preload('https://.../path/to/font.woff', { as: 'font' }) // preloads this font
  preload('https://.../path/to/stylesheet.css', { as: 'style' }) // preloads this stylesheet
  prefetchDNS('https://...') // when you may not actually request anything from this host
  preconnect('https://...') // when you will request something but aren't sure what
}

 

<!-- the above would result in the following DOM/HTML -->
<html>
  <head>
    <!-- links/scripts are prioritized by their utility to early loading, not call order -->
    <link rel="prefetch-dns" href="https://...">
    <link rel="preconnect" href="https://...">
    <link rel="preload" as="font" href="https://.../path/to/font.woff">
    <link rel="preload" as="style" href="https://.../path/to/stylesheet.css">
    <script async="" src="https://.../path/to/some/script.js"></script>
  </head>
  <body>
    ...
  </body>
</html>

 

 

 

Support for Custom Elements

React 19는 Custom Elements에 대한 완전한 지원을 추가하고 Custom Elements Everywhere에 대한 모든 테스트를 통과합니다.

 

이전 버전에서는 React가 인식되지 않는 Props를 속성이 아닌 속성으로 처리했기 때문에 React에서 Custom Elements를 사용하는 것이 어려웠습니다. React 19에서는 클라이언트 및 SSR 중에 작동하는 속성에 대한 지원을 다음과 같은 전략으로 추가했습니다.

 

Server Side Rendering: 사용자 지정 요소에 전달된 props는 해당 유형이 문자열, 숫자 또는 값이 true와 같은 기본 값이면 속성으로 렌더링됩니다. 개체, 기호, 함수 또는 값 false와 같은 primitive가 아닌 유형의 props는 생략됩니다.

Client Side Rendering: Custom Element 인스턴스의 속성과 일치하는 props는 properties로 할당되고 그렇지 않으면 attributes로 할당됩니다.

 

 

 

 

 

728x90
더보기
FRONTEND/React