React λ€λ¨κ³ νΌμμ κ°λ ₯νκ³ μ μ§μ μΈ κ²μ¦ κΈ°λ₯μ νμ©νμΈμ. useFormState ν μ μ¬μ©νμ¬ μννκ³ μλ² ν΅ν©μ μΈ μ¬μ©μ κ²½νμ ꡬμΆνλ λ°©λ²μ μμ보μΈμ.
React useFormState κ²μ¦ μμ§: λ€λ¨κ³ νΌ κ²μ¦ μ¬μΈ΅ λΆμ
νλ μΉ κ°λ°μ μΈκ³μμ μ§κ΄μ μ΄κ³ κ°λ ₯ν μ¬μ©μ κ²½νμ ꡬμΆνλ κ²μ 무μλ³΄λ€ μ€μν©λλ€. μ¬μ©μ μνΈμμ©μ μ£Όμ κ΄λ¬ΈμΈ νΌμμλ λμ± κ·Έλ μ΅λλ€. κ°λ¨ν λ¬Έμ νΌμ μ§κ΄μ μ΄μ§λ§, μ¬μ©μ λ±λ‘ λ§λ²μ¬, μ μμκ±°λ κ²°μ λλ μμΈ μ€μ ν¨λκ³Ό κ°μ λ€λ¨κ³ νΌμμλ 볡μ‘μ±μ΄ κΈ°νκΈμμ μΌλ‘ μ¦κ°ν©λλ€. μ΄λ¬ν λ€λ¨κ³ νλ‘μΈμ€λ μν κ΄λ¦¬, κ²μ¦ λ° μνν μ¬μ©μ νλ¦ μ μ§μ μλΉν μ΄λ €μμ μΌκΈ°ν©λλ€. κ³Όκ±°μλ κ°λ°μλ€μ΄ 볡μ‘ν ν΄λΌμ΄μΈνΈ μΈ‘ μν, 컨ν μ€νΈ μ 곡μ λ° νμ¬ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ‘°ν©νμ¬ μ΄λ¬ν 볡μ‘μ±μ κ΄λ¦¬ν΄μμ΅λλ€.
Reactμ `useFormState` ν μ μκ°ν©λλ€. μλ² ν΅ν© μ»΄ν¬λνΈλ₯Ό ν₯ν Reactμ λ°μ μ λ°λΌ λμ λ μ΄ κ°λ ₯ν ν μ νΉν λ€λ¨κ³ νΌμ λ§₯λ½μμ νΌ μν λ° κ²μ¦μ κ΄λ¦¬νκΈ° μν κ°μνλκ³ μ°μν μ루μ μ μ 곡ν©λλ€. μλ² μ‘μ κ³Ό μ§μ ν΅ν©ν¨μΌλ‘μ¨, `useFormState`λ μ½λλ₯Ό λ¨μννκ³ μ±λ₯μ ν₯μμν€λ©° μ μ§μ ν₯μμ μ§μνλ κ°λ ₯ν κ²μ¦ μμ§μ μμ±ν©λλ€. μ΄ κΈμ μ μΈκ³ κ°λ°μλ€μ μν΄ `useFormState`λ₯Ό μ¬μ©νμ¬ μ κ΅ν λ€λ¨κ³ κ²μ¦ μμ§μ μ€κ³νλ λ°©λ²μ λν ν¬κ΄μ μΈ κ°μ΄λλ₯Ό μ 곡νλ©°, 볡μ‘ν μμ μ κ΄λ¦¬ κ°λ₯νκ³ νμ₯ κ°λ₯ν νλ‘μΈμ€λ‘ μ νν©λλ€.
λ€λ¨κ³ νΌμ μ§μμ μΈ κ³Όμ
ν΄κ²°μ± μ μ΄ν΄λ³΄κΈ° μ μ, κ°λ°μλ€μ΄ λ€λ¨κ³ νΌμΌλ‘ μ§λ©΄νλ μΌλ°μ μΈ λ¬Έμ μ μ μ΄ν΄νλ κ²μ΄ μ€μν©λλ€. μ΄λ¬ν κ³Όμ λ μ¬μνμ§ μμΌλ©° κ°λ° μκ°λΆν° μ΅μ’ μ¬μ©μ κ²½νμ μ΄λ₯΄κΈ°κΉμ§ λͺ¨λ κ²μ μν₯μ λ―ΈμΉ μ μμ΅λλ€.
- μν κ΄λ¦¬μ 볡μ‘μ±: μ¬μ©μκ° λ¨κ³ κ°μ μ΄λν λ λ°μ΄ν°λ₯Ό μ΄λ»κ² μ μ§νλμ? μνλ λΆλͺ¨ μ»΄ν¬λνΈ, μ μ 컨ν μ€νΈ λλ λ‘컬 μ€ν 리μ§μ μμ΄μΌ ν κΉμ? κ° μ κ·Ό λ°©μμλ μ₯λ¨μ μ΄ μμΌλ©°, μ’ μ’ prop-drilling λλ 볡μ‘ν μν λκΈ°ν λ‘μ§μΌλ‘ μ΄μ΄μ§λλ€.
- κ²μ¦ λ‘μ§μ ννΈν: κ²μ¦μ μ΄λμ λ°μν΄μΌ ν κΉμ? λ§μ§λ§μ λͺ¨λ κ²μ κ²μ¦νλ©΄ μ¬μ©μ κ²½νμ΄ μ’μ§ μμ΅λλ€. κ° λ¨κ³μμ κ²μ¦νλ κ²μ΄ λ λ«μ§λ§, μ’ μ’ ν΄λΌμ΄μΈνΈ(μ¦κ°μ μΈ νΌλλ°±μ©)μ μλ²(보μ λ° λ°μ΄ν° 무결μ±μ©) λͺ¨λμμ ννΈνλ κ²μ¦ λ‘μ§μ μμ±ν΄μΌ ν©λλ€.
- μ¬μ©μ κ²½ν μ₯μ λ¬Ό: μ¬μ©μλ λ°μ΄ν°λ₯Ό μμ§ μκ³ λ¨κ³ κ°μ μλ€λ‘ μ΄λν μ μκΈ°λ₯Ό κΈ°λν©λλ€. λν λͺ ννκ³ λ§₯λ½μ λ§λ μ€λ₯ λ©μμ§μ μ¦κ°μ μΈ νΌλλ°±μ κΈ°λν©λλ€. μ΄λ¬ν μ λμ μΈ κ²½νμ ꡬννλ €λ©΄ μλΉν 보μΌλ¬νλ μ΄νΈ μ½λκ° νμν μ μμ΅λλ€.
- μλ²-ν΄λΌμ΄μΈνΈ μν λκΈ°ν: μ΅μ’ μ§μ€μ μμ²μ μΌλ°μ μΌλ‘ μλ²μ λλ€. ν΄λΌμ΄μΈνΈ μΈ‘ μνλ₯Ό μλ² μΈ‘ κ²μ¦ κ·μΉ λ° λΉμ¦λμ€ λ‘μ§κ³Ό μλ²½νκ² λκΈ°ννλ κ²μ λμμλ μΈμμ΄λ©°, μ’ μ’ μ€λ³΅ μ½λμ μ μ¬μ λΆμΌμΉλ₯Ό μΌκΈ°ν©λλ€.
μ΄λ¬ν κ³Όμ λ ν΄λΌμ΄μΈνΈμ μλ² κ°μ κ°κ·Ήμ λ©μ°λ λ³΄λ€ ν΅ν©λκ³ μμ§λ ₯ μλ μ κ·Ό λ°©μμ νμμ±μ κ°μ‘°ν©λλ€. λ°λ‘ μ¬κΈ°μ `useFormState`κ° λΉμ λ°ν©λλ€.
`useFormState` μκ°: νΌ μ²λ¦¬λ₯Ό μν νλμ μ κ·Ό λ°©μ
`useFormState` ν μ νΌ μ‘μ μ κ²°κ³Όμ λ°λΌ μ λ°μ΄νΈλλ νΌ μνλ₯Ό κ΄λ¦¬νλλ‘ μ€κ³λμμ΅λλ€. μ΄λ ν΄λΌμ΄μΈνΈμμ JavaScriptκ° νμ±νλμλ μλλ μννκ² μλνλ μ μ§μ μΌλ‘ ν₯μλ μ ν리μΌμ΄μ μ μν React λΉμ μ μ΄μμ λλ€.
`useFormState`λ 무μμΈκ°μ?
ν΅μ¬μ μΌλ‘, `useFormState`λ λ κ°μ μΈμ, μ¦ μλ² μ‘μ ν¨μμ μ΄κΈ° μνλ₯Ό λ°λ React ν μ λλ€. νμ¬ νΌ μνμ `
);
}
1λ¨κ³: κ°μΈ μ 보 μΊ‘μ² λ° κ²μ¦
μ΄ λ¨κ³μμλ `name` λ° `email` νλλ§ κ²μ¦νλ €κ³ ν©λλ€. μλ² μ‘μ μ μ΄λ€ κ²μ¦ λ‘μ§μ μ€νν μ§ μλ €μ£ΌκΈ° μν΄ μ¨κ²¨μ§ μ λ ₯ `_step`μ μ¬μ©ν©λλ€.
// Step1.jsx μ»΄ν¬λνΈ
{state.errors.name} {state.errors.email}
export function Step1({ state }) {
return (
1λ¨κ³: κ°μΈ μ 보
{state.errors?.name &&
{state.errors?.email &&
);
}
μ΄μ 1λ¨κ³ κ²μ¦μ μ²λ¦¬νλλ‘ μλ² μ‘μ μ μ λ°μ΄νΈνκ² μ΅λλ€.
// actions.js (μ
λ°μ΄νΈλ¨)
// ... (κ°μ Έμ€κΈ° λ° μ€ν€λ§ μ μ)
export async function onbordingAction(prevState, formData) {
// ... (νΌ λ°μ΄ν° κ°μ Έμ€κΈ°)
const step = Number(formData.get('_step'));
if (step === 1) {
const validatedFields = schema.pick({ name: true, email: true }).safeParse({ name, email });
if (!validatedFields.success) {
return {
...currentState,
step: 1,
errors: validatedFields.error.flatten().fieldErrors,
};
}
// μ±κ³΅, λ€μ λ¨κ³λ‘ μ΄λ
return {
...currentState,
step: 2,
errors: {},
};
}
// ... (λ€λ₯Έ λ¨κ³μ λν λ‘μ§)
}
μ¬μ©μκ° "λ€μ"μ ν΄λ¦νλ©΄ νΌμ΄ μ μΆλ©λλ€. μλ² μ‘μ μ 1λ¨κ³μΈμ§ νμΈνκ³ `name` λ° `email` νλλ§ Zodμ `pick` λ©μλλ₯Ό μ¬μ©νμ¬ κ²μ¦ν ν μ μνλ₯Ό λ°νν©λλ€. κ²μ¦μ μ€ν¨νλ©΄ μ€λ₯λ₯Ό λ°ννκ³ 1λ¨κ³μ λ¨Έλ¬Όλ¬ μμ΅λλ€. μ±κ³΅νλ©΄ μ€λ₯λ₯Ό μ§μ°κ³ `step`μ 2λ‘ μ λ°μ΄νΈνμ¬ λ©μΈ `OnboardingForm` μ»΄ν¬λνΈκ° `Step2` μ»΄ν¬λνΈλ₯Ό λ λλ§νκ² ν©λλ€.
2λ¨κ³: νμ¬ μΈλΆ μ 보μ λν μ μ§μ κ²μ¦
μ΄ μ κ·Ό λ°©μμ μ₯μ μ 1λ¨κ³μ μνκ° μλμΌλ‘ μ λ¬λλ€λ κ²μ λλ€. λ€μ νΌ μ μΆμ ν¬ν¨λλλ‘ μ¨κ²¨μ§ νλμ λ λλ§νκΈ°λ§ νλ©΄ λ©λλ€.
// Step2.jsx μ»΄ν¬λνΈ
{state.errors.companyName} {state.errors.role}
export function Step2({ state }) {
return (
2λ¨κ³: νμ¬ μΈλΆ μ 보
{/* μ΄μ λ¨κ³μ λ°μ΄ν° μ μ§ */}
{state.errors?.companyName &&
{state.errors?.role &&
);
}
κ·Έλ¦¬κ³ 2λ¨κ³μ λν μλ² μ‘μ μ μ λ°μ΄νΈν©λλ€.
// actions.js (μ
λ°μ΄νΈλ¨)
// ...
if (step === 2) {
const validatedFields = schema.pick({ companyName: true, role: true }).safeParse({ companyName, role });
if (!validatedFields.success) {
return {
...currentState,
step: 2,
errors: validatedFields.error.flatten().fieldErrors,
};
}
// μ±κ³΅, μ΅μ’
κ²ν λ‘ μ΄λ
return {
...currentState,
step: 3,
errors: {},
};
}
// ...
λ‘μ§μ 1λ¨κ³μ λμΌνμ§λ§ 2λ¨κ³ νλλ₯Ό λμμΌλ‘ ν©λλ€. `useFormState` ν μ λͺ¨λ λ°μ΄ν°λ₯Ό μ μ§νλ©΄μ μ νμ μννκ² κ΄λ¦¬νκ³ κΉ¨λνκ³ μ μ§μ μΈ κ²μ¦ νλ¦μ μ 곡ν©λλ€.
3λ¨κ³: μ΅μ’ κ²ν λ° μ μΆ
λ§μ§λ§ λ¨κ³μμλ κ²ν λ₯Ό μν΄ μμ§λ λͺ¨λ λ°μ΄ν°λ₯Ό νμν©λλ€. μ΅μ’ μ μΆμ λ°μ΄ν°λ² μ΄μ€μ 컀λ°νκΈ° μ μ λͺ¨λ νλμ λν ν¬κ΄μ μΈ κ²μ¦μ νΈλ¦¬κ±°ν©λλ€.
// Step3.jsx μ»΄ν¬λνΈ
{state.message} {state.message}
export function Step3({ state }) {
return (
3λ¨κ³: μΈλΆ μ 보 νμΈ
{state.message && state.message.startsWith('Success') &&
{state.message && state.message.startsWith('Error') &&
);
}
μ΅μ’ μλ² μ‘μ λ‘μ§μ μ 체 κ²μ¦κ³Ό μ΅μ’ λΉμ¦λμ€ λ‘μ§μ μνν©λλ€.
// actions.js (μ΅μ’
λ²μ )
// ...
if (step === 3) {
// μ΅μ’
, μ 체 κ²μ¦
const validatedFields = schema.safeParse({ name, email, companyName, role });
if (!validatedFields.success) {
// λ¨κ³λ³ κ²μ¦μ΄ μ¬λ°λ₯΄λ€λ©΄ λ°μνμ§ μμμΌ νμ§λ§, μ’μ μμ μ₯μΉμ
λλ€
return {
...currentState,
step: 1, // μ€λ₯μ ν¨κ» μ¬μ©μλ₯Ό 첫 λ²μ§Έ λ¨κ³λ‘ λ€μ 보λ
λλ€
errors: validatedFields.error.flatten().fieldErrors,
message: 'μ€λ₯: λ°μ΄ν°μ μ ν¨νμ§ μμ νλͺ©μ΄ μμ΅λλ€. λ€μ κ²ν ν΄ μ£ΌμΈμ.'
};
}
try {
// console.log('λ°μ΄ν°λ² μ΄μ€μ μ μΆ μ€:', validatedFields.data);
// await saveToDatabase(validatedFields.data);
return { message: 'μ±κ³΅! μ¨λ³΄λ©μ΄ μλ£λμμ΅λλ€.', step: 4 }; // μ΅μ’
μ±κ³΅ λ¨κ³
} catch (dbError) {
return { ...currentState, step: 3, message: 'μ€λ₯: λ°μ΄ν°λ₯Ό μ μ₯ν μ μμ΅λλ€.' };
}
}
// ...
μ΄λ₯Ό ν΅ν΄ μ°λ¦¬λ `useFormState` ν μΌλ‘ κΉλνκ² μ‘°μ¨λ, μμ νκ³ κ°λ ₯ν λ€λ¨κ³ νΌκ³Ό μ μ§μ μ΄λ©° μλ² κΆνμ κ²μ¦ κΈ°λ₯μ κ°μΆκ² λμμ΅λλ€.
μ΅κ³ μμ€μ μ¬μ©μ κ²½νμ μν κ³ κΈ μ λ΅
κΈ°λ₯μ μΈ νΌμ ꡬμΆνλ κ²μ ν κ°μ§μ΄κ³ , μ¬μ©νκΈ° μ¦κ²κ² λ§λλ κ²μ λ λ€λ₯Έ κ²μ λλ€. λ€μμ λ€λ¨κ³ νΌμ ν₯μμν€κΈ° μν κ³ κΈ κΈ°λ²μ λλ€.
νμ κ΄λ¦¬: μλ€λ‘ μ΄λ
νμ¬ λ‘μ§μ μμΌλ‘λ§ μ΄λν©λλ€. μ¬μ©μκ° λ€λ‘ κ° μ μλλ‘ νλ €λ©΄ κ°λ¨ν `type="submit"` λ²νΌμ μ¬μ©ν μ μμ΅λλ€. λμ ν΄λΌμ΄μΈνΈ μΈ‘ μ»΄ν¬λνΈ μνμμ λ¨κ³λ₯Ό κ΄λ¦¬νκ³ νΌ μ‘μ μ μμΌλ‘μ μ§νμλ§ μ¬μ©ν΄μΌ ν©λλ€. κ·Έλ¬λ μλ² μ€μ¬ λͺ¨λΈμ κ³ μνλ λ κ°λ¨ν μ κ·Ό λ°©μμ νΌμ μ μΆνμ§λ§ λ€λ₯Έ μλλ₯Ό κ°μ§ "λ€λ‘ κ°κΈ°" λ²νΌμ κ°λ κ²μ λλ€.
// λ¨κ³ μ»΄ν¬λνΈμμ...
// μλ² μ‘μ
μμ...
const intent = formData.get('intent');
if (intent === 'back') {
return { ...currentState, step: step - 1, errors: {} };
}
`useFormStatus`λ‘ μ¦κ°μ μΈ νΌλλ°± μ 곡
`useFormStatus` ν μ λμΌν `
// SubmitButton.jsx
'use client';
import { useFormStatus } from 'react-dom';
export function SubmitButton({ text }) {
const { pending } = useFormStatus();
return (
{pending ? 'μ μΆ μ€...' : text}
);
}
κ·Έλ° λ€μ λ¨κ³ μ»΄ν¬λνΈμμ νμ€ `
νμ₯μ±μ μν μλ² μ‘μ ꡬ쑰ν
νΌμ΄ 컀μ§μ λ°λΌ μλ² μ‘μ μ `if/else if` 체μΈμ λ€λ£¨κΈ° μ΄λ €μμ§ μ μμ΅λλ€. λ λμ ꡬμ±μ μν΄ `switch` λ¬Έ λλ λ λͺ¨λνλ ν¨ν΄μ΄ κΆμ₯λ©λλ€.
// switch λ¬Έμ΄ μλ actions.js
switch (step) {
case 1:
// 1λ¨κ³ κ²μ¦ μ²λ¦¬
break;
case 2:
// 2λ¨κ³ κ²μ¦ μ²λ¦¬
break;
// ... λ±λ±
}
μ κ·Όμ± (a11y)μ νμ λΆκ°
μ μΈκ³ μ¬μ©μλ₯Ό μν΄ μ κ·Όμ±μ νμμ λλ€. λ€μμ ν΅ν΄ νΌμ΄ μ κ·Ό κ°λ₯νλλ‘ νμΈμ:
- μ€λ₯κ° μλ μ λ ₯ νλμ `aria-invalid="true"` μ¬μ©.
- `aria-describedby`λ₯Ό μ¬μ©νμ¬ μ€λ₯ λ©μμ§λ₯Ό μ λ ₯μ μ°κ²°.
- νΉν μ€λ₯κ° λνλ λ μ μΆ ν ν¬μ»€μ€λ₯Ό μ μ νκ² κ΄λ¦¬.
- λͺ¨λ νΌ μ»¨νΈλ‘€μ΄ ν€λ³΄λλ‘ νμ κ°λ₯νμ§ νμΈ.
κΈλ‘λ² κ΄μ : κ΅μ ν λ° `useFormState`
μλ² μ£Όλ κ²μ¦μ μ€μν μ΄μ μ€ νλλ κ΅μ ν(i18n)κ° μ©μ΄νλ€λ κ²μ λλ€. κ²μ¦ λ©μμ§λ₯Ό ν΄λΌμ΄μΈνΈμμ νλμ½λ©ν νμκ° λ μ΄μ μμ΅λλ€. μλ² μ‘μ μ μ¬μ©μ κΈ°λ³Έ μΈμ΄( `Accept-Language`μ κ°μ ν€λ, URL λ§€κ°λ³μ λλ μ¬μ©μ νλ‘ν μ€μ )λ₯Ό κ°μ§νκ³ ν΄λΉ μΈμ΄λ‘ μ€λ₯λ₯Ό λ°νν μ μμ΅λλ€.
μλ₯Ό λ€μ΄, μλ²μμ `i18next`μ κ°μ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ κ²½μ°:
// i18nμ΄ μλ μλ² μ‘μ
import { i18n } from 'your-i18n-config';
// ...
const t = await i18n.getFixedT(userLocale); // μ: μ€νμΈμ΄μ κ²½μ° 'es'
const schema = z.object({
email: z.string().email(t('errors.invalid_email')),
});
μ΄ μ κ·Ό λ°©μμ μ μΈκ³ μ¬μ©μκ° λͺ ννκ³ μ΄ν΄νκΈ° μ¬μ΄ νΌλλ°±μ λ°λλ‘ λ³΄μ₯νμ¬ μ ν리μΌμ΄μ μ ν¬μ©μ±κ³Ό μ¬μ©μ±μ ν¬κ² ν₯μμν΅λλ€.
`useFormState` λ ν΄λΌμ΄μΈνΈ μΈ‘ λΌμ΄λΈλ¬λ¦¬: λΉκ΅ λΆμ
μ΄ ν¨ν΄μ Formik λλ React Hook Formκ³Ό κ°μ κΈ°μ‘΄ λΌμ΄λΈλ¬λ¦¬μ μ΄λ»κ² λΉκ΅λ κΉμ? μ΄λ κ²μ΄ λ μ’μμ§κ° μλλΌ μ΄λ€ κ²μ΄ μμ μ μ ν©νμ§μ λν κ²μ λλ€.
- ν΄λΌμ΄μΈνΈ μΈ‘ λΌμ΄λΈλ¬λ¦¬ (Formik, React Hook Form): μ΄λ¬ν λΌμ΄λΈλ¬λ¦¬λ μ¦κ°μ μΈ ν΄λΌμ΄μΈνΈ μΈ‘ νΌλλ°±μ΄ μ΅μ°μ κ³Όμ μΈ λ³΅μ‘νκ³ λ§€μ° μνΈ μμ©μ μΈ νΌμ νλ₯ν©λλ€. νΌ μν, κ²μ¦ λ° μ μΆμ λΈλΌμ°μ λ΄μμ μμ ν κ΄λ¦¬νκΈ° μν ν¬κ΄μ μΈ ν΄ν·μ μ 곡ν©λλ€. μ£Όμ κ³Όμ λ ν΄λΌμ΄μΈνΈμ μλ² κ°μ κ²μ¦ λ‘μ§ μ€λ³΅μΌ μ μμ΅λλ€.
- μλ² μ‘μ κ³Ό ν¨κ»νλ `useFormState`: μ΄ μ κ·Ό λ°©μμ μλ²κ° μ΅μ’ μ§μ€μ μμ²μΈ κ³³μμ νμν©λλ€. λ‘μ§μ μ€μ μ§μ€ννμ¬ μ 체 μν€ν μ²λ₯Ό λ¨μννκ³ , λ°μ΄ν° 무결μ±μ 보μ₯νλ©°, μ μ§μ ν₯μκ³Ό μλ²½νκ² μλν©λλ€. λ¨μ μ κ²μ¦μ μν΄ λ€νΈμν¬ μλ³΅μ΄ νμνλ€λ κ²μ΄μ§λ§, νλ μΈνλΌμμλ μ’ μ’ λ¬΄μν μ μλ μμ€μ λλ€.
λ°μ΄ν°λ² μ΄μ€μ κ²μ¦ν΄μΌ νλ μλΉν λΉμ¦λμ€ λ‘μ§ λλ λ°μ΄ν° (μ: μ¬μ©μ μ΄λ¦μ΄ μ¬μ© μ€μΈμ§ νμΈ)λ₯Ό ν¬ν¨νλ λ€λ¨κ³ νΌμ κ²½μ°, `useFormState` ν¨ν΄μ λ μ§μ μ μ΄κ³ μ€λ₯κ° μ μ μν€ν μ²λ₯Ό μ 곡ν©λλ€.
κ²°λ‘ : React νΌμ λ―Έλ
`useFormState` ν μ λ¨μν μλ‘μ΄ API κ·Έ μ΄μμ λλ€. Reactμμ νΌμ ꡬμΆνλ λ°©λ²μ λν μ² νμ λ³νλ₯Ό λνλ λλ€. μλ² μ€μ¬ λͺ¨λΈμ μ±νν¨μΌλ‘μ¨ μ°λ¦¬λ λ κ°λ ₯νκ³ μμ νλ©° μ κ·Ό κ°λ₯νκ³ μ μ§ κ΄λ¦¬κ° λ μ¬μ΄ λ€λ¨κ³ νΌμ λ§λ€ μ μμ΅λλ€. μ΄ ν¨ν΄μ μν λκΈ°νμ κ΄λ ¨λ λͺ¨λ μ’ λ₯μ λ²κ·Έλ₯Ό μ κ±°νκ³ λ³΅μ‘ν μ¬μ©μ νλ¦μ μ²λ¦¬νκΈ° μν λͺ ννκ³ νμ₯ κ°λ₯ν ꡬ쑰λ₯Ό μ 곡ν©λλ€.
`useFormState`λ‘ κ²μ¦ μμ§μ ꡬμΆν¨μΌλ‘μ¨ λ¨μν μνλ₯Ό κ΄λ¦¬νλ κ²μ΄ μλλΌ, νλ μΉ κ°λ° μμΉμ κΈ°λ°ν 볡μλ ₯ μκ³ μ¬μ©μ μΉνμ μΈ λ°μ΄ν° μμ§ νλ‘μΈμ€λ₯Ό μ€κ³νλ κ²μ λλ€. λ€μνκ³ κΈλ‘λ²ν μ²μ€μ μν μ ν리μΌμ΄μ μ ꡬμΆνλ κ°λ°μμκ² μ΄ κ°λ ₯ν ν μ μ§μ ν μΈκ³μ μμ€μ μ¬μ©μ κ²½νμ λ§λ€κΈ° μν κΈ°λ°μ μ 곡ν©λλ€.