useFormStatus - This feature is available in the latest Canary

Canary

useFormStatus Hook์€ ํ˜„์žฌ React์˜ Canary ์ฑ„๋„๊ณผ ์‹คํ—˜์ ์ธ ์ฑ„๋„์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ React ๋ฆด๋ฆฌ์ฆˆ ์ฑ„๋„์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

useFormStatus๋Š” ๋งˆ์ง€๋ง‰ ํผ ์ œ์ถœ์˜ ์ƒํƒœ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” Hook์ž…๋‹ˆ๋‹ค.

const { pending, data, method, action } = useFormStatus();

๋ ˆํผ๋Ÿฐ์Šค

useFormStatus()

useFormStatus Hook์€ ๋งˆ์ง€๋ง‰ ํผ ์ œ์ถœ์˜ ์ƒํƒœ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

import { useFormStatus } from "react-dom";
import action from './actions';

function Submit() {
const status = useFormStatus();
return <button disabled={status.pending}>Submit</button>
}

export default function App() {
return (
<form action={action}>
<Submit />
</form>
);
}

์ƒํƒœ ์ •๋ณด๋ฅผ ์ œ๊ณต๋ฐ›๊ธฐ ์œ„ํ•ด Submit ์ปดํฌ๋„ŒํŠธ๋ฅผ <form> ๋‚ด๋ถ€์— ๋ Œ๋”๋งํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด Hook์€ ํผ์ด ํ˜„์žฌ ์ œ์ถœํ•˜๊ณ  ์žˆ๋Š” ์ƒํƒœ์ธ์ง€๋ฅผ ์˜๋ฏธํ•˜๋Š” pending ํ”„๋กœํผํ‹ฐ์™€ ๊ฐ™์€ ์ƒํƒœ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์œ„์˜ ์˜ˆ์‹œ์—์„œ Submit ์ปดํฌ๋„ŒํŠธ๋Š” ํผ์ด ์ œ์ถœ ์ค‘์ผ ๋•Œ <button>์„ ๋ˆ„๋ฅผ ์ˆ˜ ์—†๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด ์ด ์ •๋ณด๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜์—์„œ ๋” ๋งŽ์€ ์˜ˆ์‹œ๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”.

๋งค๊ฐœ๋ณ€์ˆ˜

useFormStatus์€ ์–ด๋–ค ๋งค๊ฐœ๋ณ€์ˆ˜๋„ ๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๊ฐ’

๋‹ค์Œ์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๋Š” status ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค:

  • pending: ๋ถˆ๋ฆฌ์–ธ ๊ฐ’์ž…๋‹ˆ๋‹ค. true๋ผ๋ฉด ์ƒ์œ„ <form>์ด ์•„์ง ์ œ์ถœ ์ค‘์ด๋ผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด false์ž…๋‹ˆ๋‹ค.

  • data: FormData ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฐ์ฒด๋กœ, ์ƒ์œ„ <form>์ด ์ œ์ถœํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ํ™œ์„ฑํ™”๋œ ์ œ์ถœ์ด ์—†๊ฑฐ๋‚˜ ์ƒ์œ„์— <form>์ด ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” null์ž…๋‹ˆ๋‹ค.

  • method: 'get' ๋˜๋Š” 'post' ์ค‘ ํ•˜๋‚˜์˜ ๋ฌธ์ž์—ด ๊ฐ’์ž…๋‹ˆ๋‹ค. ์ด ํ”„๋กœํผํ‹ฐ๋Š” ์ƒ์œ„ <form>์ด GET ๋˜๋Š” POST HTTP ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ œ์ถœ๋˜๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ <form>์€ GET ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ method ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • action: ์ƒ์œ„ <form>์˜ action prop์— ์ „๋‹ฌํ•œ ํ•จ์ˆ˜์˜ ๋ ˆํผ๋Ÿฐ์Šค์ž…๋‹ˆ๋‹ค. ์ƒ์œ„ <form>์ด ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” ์ด ํ”„๋กœํผํ‹ฐ๋Š” null์ž…๋‹ˆ๋‹ค. action prop์— URI ๊ฐ’์ด ์ œ๊ณต๋˜์—ˆ๊ฑฐ๋‚˜ action prop๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ์—๋Š” status.action์€ null์ž…๋‹ˆ๋‹ค.

์ฃผ์˜ ์‚ฌํ•ญ

  • useFormStatus Hook์€ <form> ๋‚ด๋ถ€์— ๋ Œ๋”๋งํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • useFormStatus๋Š” ์˜ค์ง ์ƒ์œ„ <form>์— ๋Œ€ํ•œ ์ƒํƒœ ์ •๋ณด๋งŒ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ๋‚˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ Œ๋”๋งํ•œ <form>์˜ ์ƒํƒœ ์ •๋ณด๋Š” ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋ฒ•

ํผ์„ ์ œ์ถœํ•˜๋Š” ๋™์•ˆ ๋ณด๋ฅ˜ ์ค‘์ธ ์ƒํƒœ๋กœ ํ‘œ์‹œํ•˜๊ธฐ

ํผ์„ ์ œ์ถœํ•˜๋Š” ๋™์•ˆ ๋ณด๋ฅ˜ ์ƒํƒœ๋ฅผ ํ‘œ์‹œํ•˜๋ ค๋ฉด <form> ๋‚ด์—์„œ ๋ Œ๋”๋งํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ useFormStatus Hook์„ ํ˜ธ์ถœํ•˜๊ณ  ๋ฐ˜ํ™˜๋œ pending ํ”„๋กœํผํ‹ฐ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

์—ฌ๊ธฐ์„œ๋Š” pending ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํผ์ด ์ œ์ถœ ์ค‘์ธ์ง€๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

import { useFormStatus } from "react-dom";
import { submitForm } from "./actions.js";

function Submit() {
  const { pending } = useFormStatus();
  return (
    <button type="submit" disabled={pending}>
      {pending ? "Submitting..." : "Submit"}
    </button>
  );
}

function Form({ action }) {
  return (
    <form action={action}>
      <Submit />
    </form>
  );
}

export default function App() {
  return <Form action={submitForm} />;
}

์ฃผ์˜ํ•˜์„ธ์š”!

useFormStatus๋Š” ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ Œ๋”๋งํ•œ <form>์— ๋Œ€ํ•œ ์ƒํƒœ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

useFormStatus Hook์€ ์ƒ์œ„ <form>์— ๋Œ€ํ•œ ์ •๋ณด๋งŒ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. Hook์„ ํ˜ธ์ถœํ•˜๋Š” ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ๋‚˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ Œ๋”๋งํ•œ <form>์˜ ์ƒํƒœ ์ •๋ณด๋Š” ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

function Form() {
// ๐Ÿšฉ `pending`์€ ์ ˆ๋Œ€ true๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
// useFormStatus๋Š” ํ˜„์žฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ Œ๋”๋งํ•œ ํผ์„ ์ถ”์ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
const { pending } = useFormStatus();
return <form action={submit}></form>;
}

๋Œ€์‹  <form> ๋‚ด๋ถ€์— ์œ„์น˜ํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ useFormStatus๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

function Submit() {
// โœ… `pending`์€ Submit ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ๋Š” ํผ์—์„œ ํŒŒ์ƒ๋ฉ๋‹ˆ๋‹ค
const { pending } = useFormStatus();
return <button disabled={pending}>...</button>;
}

function Form() {
// `useFormStatus`๊ฐ€ ์ถ”์ ํ•˜๋Š” <form>์ž…๋‹ˆ๋‹ค
return (
<form action={submit}>
<Submit />
</form>
);
}

์ œ์ถœํ•œ ํผ ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ

useFormStatus์—์„œ ๋ฐ˜ํ™˜๋œ ์ƒํƒœ ์ •๋ณด์˜ data ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ œ์ถœํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฆ„์„ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋Š” ํผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. useFormStatus๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•œ ์‚ฌ์šฉ์ž ์ด๋ฆ„์„ ํ™•์ธํ•˜๋Š” ์ž„์‹œ ์ƒํƒœ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import {useState, useMemo, useRef} from 'react';
import {useFormStatus} from 'react-dom';

export default function UsernameForm() {
  const {pending, data} = useFormStatus();

  const [showSubmitted, setShowSubmitted] = useState(false);
  const submittedUsername = useRef(null);
  const timeoutId = useRef(null);

  useMemo(() => {
    if (pending) {
      submittedUsername.current = data?.get('username');
      if (timeoutId.current != null) {
        clearTimeout(timeoutId.current);
      }

      timeoutId.current = setTimeout(() => {
        timeoutId.current = null;
        setShowSubmitted(false);
      }, 2000);
      setShowSubmitted(true);
    }
  }, [pending, data]);

  return (
    <>
      <label>Request a Username: </label><br />
      <input type="text" name="username" />
      <button type="submit" disabled={pending}>
        {pending ? 'Submitting...' : 'Submit'}
      </button>
      {showSubmitted ? (
        <p>Submitted request for username: {submittedUsername.current}</p>
      ) : null}
    </>
  );
}


๋ฌธ์ œ ํ•ด๊ฒฐ

status.pending์ด ์ ˆ๋Œ€๋กœ true๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

useFormStatus๋Š” ์˜ค์ง ์ƒ์œ„ <form>์— ๋Œ€ํ•œ ์ƒํƒœ ์ •๋ณด๋งŒ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

useFormStatus๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ <form>์— ๊ฐ์‹ธ์ ธ ์žˆ์ง€ ์•Š๋‹ค๋ฉด, status.pending์€ ํ•ญ์ƒ false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. useFormStatus๊ฐ€ <form> ์—˜๋ฆฌ๋จผํŠธ์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—์„œ ํ˜ธ์ถœ๋˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.

useFormStatus๋Š” ๋™์ผํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ Œ๋”๋งํ•œ <form>์˜ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ฃผ์˜ํ•˜์„ธ์š”! ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.