[Hook] useActionState

OlMinJe·2025년 8월 31일

React

목록 보기
2/19

리액트 공식 문서를 참고한 정리 내용 (25.08 기준)

form 액션의 결과를 기반으로 State를 업데이트할 수 있게 제공한다.

useActionState는 기존의 폼 액션 함수와 초기 State를 전달받고, 폼에서 사용할 새로운 액션을 반환한다. 또한 최신 폼 State와 액션이 대기 중인지 여부(isPending)도 반환한다.
이떄 최신 폼 State는 useActionState에 전달한 함수에도 함께 전달된다.

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

매개변수

fn

폼이 제출되거나 버튼이 눌렀을 때 호출되는 함수

  • 함수가 호출되면 첫 번째 인수로 폼의 이전 State(처음에 전달한 intialState, 이후에는 이전 반환값)가 전달되고, 그 뒤로는 폼 액션이 일반적으로 받는 인수들이 전달된다.

👉 즉, "폼이 실행될 때 무슨 일을 할지" 정해주는 함수

intialState

  • 처음에 가지기를 원하는 값으로, 직렬화 가능한 값이라면 무엇이든 OK

👉 쉽게 말하면 “폼이 시작할 때 기본값”

해당 폼이 수정하는 페이지 URL을 포함하는 문자열

  • 이게 무슨 말이냐면, 우선 특수한 상황에 쓰인다.
  • 만약 페이지에 동적인 콘텐츠가 있고, 자바스크립트가 아직 로드되기 전에 폼을 제출했다면, 브라우저는 그냥 현재 페이지에 머무는 대신 permalink(고유한 URL)로 이동한다,
  • 이렇게 하면 React가 나중에 하이드레이션(클라이언트 쪽 React 실행)을 할 때, 동일한 폼 컨포넌트를 다시 찾아서 상태를 이어받을 수 있다.

👉 JS가 늦게 로드되더라도 페이지가 끊기지 않고 자연스럽게 동작하도록 도와주는 옵션이다.


반환값

다음 세 가지 값을 담은 배열을 반환한다.

현재 State

  • 첫 렌더링 시에는 initialState와 일치
  • 폼이 제출되어 액션 함수(fn)가 실행되면, 그 반환값이 이 state로 바뀐다.

    👉 “폼의 현재 결과 상태”

새 액션 함수

  • formaction prop이나 버튼의 formAction prop에 넣을 수 있는 함수이다.
  • 원래 fn을 그냥 쓰는 게 아니라, useActionState가 상태랑 연결된 래퍼 함수를 돌려주는 거라고 보면 된다.
  • 필요하면 startTransition 안에서 수동으로 직접 호출할 수 있다.

    👉 “폼 제출 시 실행할 액션 함수(상태랑 연결된 버전)”

###isPending (대기 중 여부)

  • 현재 Transition이 대기 중인지 알려주는 isPending 플래그이다.
  • 액션이 실행 중인지 알려주는 Boolean 값
  • 로딩 스피너 띄우거나, 버튼 비활성화 등에 활용한다

    👉 “폼 제출이 처리 중인지 알려주는 깃발”

import { useActionState } from "react";

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

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

주의사항

  • 서버 컴포넌트를 지원하는 프레임워크에서 useActionState를 사용하면, Client는 자바스크립트 실행 전에도 폼과 상호작용할 수 있다.
    만약 서버 컴포넌트를 사용하지 않는다면, 컴포넌트 지역 State와 동일하게 동작한다.
  • useActionState에 전달된 함수는 첫 번째 인수로 이전 또는 초기 State를 추가로 받는다.
    즉, 직접 폼 액션을 사용했을 때와 비교해 함수의 시그니처가 달라질 수 있다

💬 useActionState(fn, initialState)에 넣는 fn첫 번째 인수로 이전 state를 무조건 받는다. 즉 , fn(prevState, …기타 폼 데이터)
하지만 일반 폼 액션 함수를 사용하면 보통 첫 번째 인수가 formData 같은 데이터이다. 그래서 useActionState를 사용할 때는 함수 정의 방식이 약간 달라진다.

// 일반 폼 액션
async function submit(formData) {
  // formData만 받음
}
// useActionState에서 쓰는 액션
async function submit(prevState, formData) {
  // 이전 state와 formData 모두 받음
}

👉 서버 컴포넌트 환경에서는 JS 없이도 폼이 동작하고, useActionState에 넘기는 함수는 첫 번째 인수로 이전 state를 받기 때문에 일반 폼 액션과 함수 모양이 조금 다르다.


사용법

import { useActionState } from "react";
import { addToCart } from "./actions.js";

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

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

export async function addToCart(prevState, queryData) {
  const itemID = queryData.get('itemID');
  if (itemID === "1") {
    return "Added to cart";
  } else {
    await new Promise(resolve => setTimeout(resolve, 2000));
    return "Couldn't add to cart: the item is sold out.";
  }
}
  1. 현재 State는, 처음에 전달한 초기 State로 설정되며, 폼이 제출된 이후에는 액션의 반환값으로 설정된다.
  2. <form>action Prop에 전달하거나 startTransition 안에서 직접 호출할 수 있는 새로운 액션이다.
  3. 액션이 처리되는 동안 사용할 수 있는 대기 State이다.
  4. isPending으로 실행 처리 여부를 확인할 수 있다..
profile
큐트걸

0개의 댓글