useFormState - This feature is available in the latest Canary

Canary

useFormState Hook은 현재 React의 Canary 채널과 실험적인 채널에서만 사용할 수 있습니다. 자세한 내용은 React 릴리즈 채널에서 확인할 수 있습니다. 또한 useFormState의 모든 이점을 얻으려면 React Server Components를 지원하는 프레임워크를 사용해야 합니다.

useFormState는 폼 액션의 결과를 기반으로 state를 업데이트할 수 있도록 제공하는 Hook입니다.

const [state, formAction] = useFormState(fn, initialState, permalink?);

레퍼런스

useFormState(action, initialState, permalink?)

컴포넌트 최상위 레벨에서 useFormState를 호출하여 폼 액션이 실행될 때 업데이트되는 컴포넌트 state를 생성합니다. useFormState에 기존의 폼 작업 함수와 초기 state를 전달하면, 최신 폼 state와 함께 폼에서 사용하는 새로운 액션을 반환합니다. 최신 폼 state 또한 제공된 함수에 전달됩니다.

import { useFormState } from "react-dom";

async function increment(previousState, formData) {
return previousState + 1;
}

function StatefulForm({}) {
const [state, formAction] = useFormState(increment, 0);
return (
<form>
{state}
<button formAction={formAction}>Increment</button>
</form>
)
}

폼 state는 폼을 마지막으로 제출했을 때 액션에서 반환되는 값입니다. 폼이 제출되기 전이라면 전달한 초기 state와 같습니다.

Server Action과 함께 사용하는 경우, useFormState를 사용하여 hydration이 완료되기 전에도 폼 제출에 대한 서버의 응답을 보여줄 수 있습니다.

아래에서 더 많은 예시를 확인해 보세요.

매개변수

  • fn: 폼이 제출되거나 버튼을 눌렀을 때 호출될 함수입니다. 함수가 실행될 때, 첫 번째 인수로 폼의 이전 state를 전달합니다. state는 초기에 전달한 initialState이고, 이후에는 이전 실행의 반환값입니다. 그 후 일반적으로 폼 액션에 전달하는 인수들이 이어집니다.
  • initialState: 초기 state로 설정하고자 하는 값으로, 직렬화 할 수 있는 값일 수 있습니다. 액션이 처음 호출된 후에는 이 인수를 무시합니다.
  • optional permalink: A string containing the unique page URL that this form modifies. For use on pages with dynamic content (eg: feeds) in conjunction with progressive enhancement: if fn is a server action and the form is submitted before the JavaScript bundle loads, the browser will navigate to the specified permalink URL, rather than the current page’s URL. Ensure that the same form component is rendered on the destination page (including the same action fn and permalink) so that React knows how to pass the state through. Once the form has been hydrated, this parameter has no effect.

반환값

useFormState는 정확히 두 개의 값이 담긴 배열을 반환합니다.

  1. 현재 state입니다. 첫 번째 렌더링에서는 전달한 initialState와 일치합니다. 액션이 실행된 이후에는 액션에서 반환한 값과 일치합니다.
  2. form 컴포넌트의 action prop에 전달하거나 폼 내부 button 컴포넌트의 formAction prop에 전달할 수 있는 새로운 액션입니다.

주의 사항

  • React Server Components를 지원하는 프레임워크와 함께 사용할 때, useFormState는 클라이언트에서 자바스크립트가 실행되기 이전에도 폼을 상호작용하도록 만들 수 있습니다. Server Components를 사용하지 않는다면 컴포넌트 지역 state와 동일합니다.
  • useFormState에 전달한 함수는 첫 번째 인수로 이전 혹은 초기 state를 추가로 받습니다. 이를 통해 useFormState를 사용하지 않고 직접 폼 액션을 사용했을 경우와는 다른 시그니처를 가지게 됩니다.

사용법

폼 액션에서 반환된 정보 사용하기

컴포넌트의 최상위 레벨에서 useFormState를 호출하면 폼이 마지막으로 제출된 시점에 액션이 반환한 값에 접근할 수 있습니다.

import { useFormState } from 'react-dom';
import { action } from './actions.js';

function MyComponent() {
const [state, formAction] = useFormState(action, null);
// ...
return (
<form action={formAction}>
{/* ... */}
</form>
);
}

useFormState는 정확히 두 개의 항목으로 구성된 배열을 반환합니다.

  1. 폼의 현재 state입니다. 처음에는 제공한 초기 state로 설정되며, 폼이 제출된 후에는 전달한 액션의 반환값으로 설정됩니다.
  2. <form>action prop에 전달할 새로운 action입니다.

폼을 제출하면 전달한 액션 함수가 호출됩니다. 액션의 반환값은 폼의 새로운 현재 state가 됩니다.

전달한 액션은 또한 폼의 현재 state를 새로운 첫 번째 인수로 받게 됩니다. 폼이 처음 제출되면 제공한 초기 state이며, 이후 제출에서는 액션이 마지막으로 호출된 시점의 반환값이 됩니다. 나머지 인수는 useFormState를 사용하지 않았을 때와 동일합니다.

function action(currentState, formData) {
// ...
return 'next state';
}

폼 제출 후 정보 표시하기

예제 1 of 2:
오류 표시하기

Server Action에서 반환한 오류 메시지나 토스트와 같은 메시지를 표시하려면 해당 액션을 useFormState 호출로 감싸세요.

import { useState } from "react";
import { useFormState } from "react-dom";
import { addToCart } from "./actions.js";

function AddToCartForm({itemID, itemTitle}) {
  const [message, formAction] = useFormState(addToCart, null);
  return (
    <form action={formAction}>
      <h2>{itemTitle}</h2>
      <input type="hidden" name="itemID" value={itemID} />
      <button type="submit">Add to Cart</button>
      {message}
    </form>
  );
}

export default function App() {
  return (
    <>
      <AddToCartForm itemID="1" itemTitle="JavaScript: The Definitive Guide" />
      <AddToCartForm itemID="2" itemTitle="JavaScript: The Good Parts" />
    </>
  )
}

문제 해결

액션이 더 이상 제출된 폼 데이터를 읽을 수 없습니다

액션을 useFormState로 감싸면 첫 번째 인수를 추가로 전달받습니다. 따라서 제출된 폼 데이터는 보통의 경우처럼 첫 번째로 전달되는 대신 두 번째 인수가 됩니다. 새롭게 추가된 첫 번째 인수는 폼의 현재 state입니다.

function action(currentState, formData) {
// ...
}