๊ฒฌ๊ณ ํ ํผ ์ค๋ฅ ์ฒ๋ฆฌ, ์ ์ถ ์ถ์ , ํฅ์๋ ์ฌ์ฉ์ ๊ฒฝํ์ ์ํ React์ experimental_useFormStatus ํ ์ฌ์ธต ๋ถ์. ํ๋ ฅ ์๊ณ ์ฌ์ฉ์ ์นํ์ ์ธ ํผ ๊ตฌ์ถ ๋ฐฉ๋ฒ์ ๋ฐฐ์ฐ์ธ์.
React experimental_useFormStatus: ํผ ์ค๋ฅ ์ํ ์ถ์ ๋ง์คํฐํ๊ธฐ
๋์์์ด ๋ฐ์ ํ๋ React์ ์ํ๊ณ๋ ๊ฐ๋ฐ์ ๋จ์ํํ๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๋ ๊ฒ์ ๋ชฉํ๋ก ํ๋ ๊ธฐ๋ฅ๋ค์ ์ง์์ ์ผ๋ก ์ ๋ณด์ด๊ณ ์์ต๋๋ค. ์ต๊ทผ์ ์ถ๊ฐ๋ ๊ธฐ๋ฅ ์ค ํ๋๋ก, ํ์ฌ ์คํ ๋จ๊ณ์ ์๋ ๊ฒ์ด ๋ฐ๋ก experimental_useFormStatus ํ
์
๋๋ค. ์ด ๊ฐ๋ ฅํ ๋๊ตฌ๋ React ์ปดํฌ๋ํธ ๋ด์์ ์ง์ ์ ์ผ๋ก ์ค๋ฅ ์ํ๋ฅผ ํฌํจํ ํผ ์ ์ถ ์ํ๋ฅผ ์ถ์ ํ๋ ๊ฐ์ํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์ด ๋ธ๋ก๊ทธ ํฌ์คํธ๋ ๊ฒฌ๊ณ ํ๊ณ ์ฌ์ฉ์ ์นํ์ ์ธ ํผ์ ๊ตฌ์ถํ๊ธฐ ์ํด experimental_useFormStatus๋ฅผ ์ดํดํ๊ณ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํ ํฌ๊ด์ ์ธ ๊ฐ์ด๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
experimental_useFormStatus์ ํ์์ฑ ์ดํดํ๊ธฐ
์ ํต์ ์ผ๋ก React์์ ํผ ์ ์ถ์ ๊ด๋ฆฌํ๋ ๋ฐ๋ ์๋นํ ์์ ์์ฉ๊ตฌ(boilerplate) ์ฝ๋๊ฐ ํ์ํ์ต๋๋ค. ๊ฐ๋ฐ์๋ค์ ์๋์ผ๋ก ์ ์ถ ์ํ(๋๊ธฐ, ์ฑ๊ณต, ์ค๋ฅ)๋ฅผ ์ถ์ ํ๊ณ , ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ๋ฉฐ, ๊ทธ์ ๋ฐ๋ผ UI๋ฅผ ์ ๋ฐ์ดํธํด์ผ ํ์ต๋๋ค. ์ด๋ ํนํ ์ฌ๋ฌ ์ ํจ์ฑ ๊ฒ์ฌ ๊ท์น๊ณผ ๋น๋๊ธฐ ์์ ์ด ์๋ ๋ณต์กํ ํผ์์ ์ฝ๋๋ฅผ ๋ณต์กํ๊ณ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค ์ ์์์ต๋๋ค.
experimental_useFormStatus๋ ํผ ์ ์ถ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ์ค์ ์ง์ค์ ์ด๊ณ ์ ์ธ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํจ์ผ๋ก์จ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค. ์ด๋ ์ค๋ฅ ์ถ์ , ๋ก๋ฉ ์ํ ํ์, ์ฌ์ฉ์์๊ฒ ํผ๋๋ฐฑ ์ ๊ณต ๊ณผ์ ์ ๋จ์ํํ์ฌ ๋ ๊นจ๋ํ๊ณ ์ ์ง ๊ด๋ฆฌ๊ฐ ์ฌ์ฐ๋ฉฐ ์ฑ๋ฅ์ด ๋ฐ์ด๋ ์ฝ๋๋ฅผ ๋ง๋ค ์ ์๊ฒ ํด์ค๋๋ค.
experimental_useFormStatus๋ ๋ฌด์์ธ๊ฐ?
experimental_useFormStatus ํ
์ ํผ ์ ์ถ ์ํ์ ๋ํ ์ ๋ณด๋ฅผ ์ ๊ณตํ๊ธฐ ์ํด ํน๋ณํ ์ค๊ณ๋ React ํ
์
๋๋ค. ์ด๋ <form> ์์์ action ์์ฑ ๋ฐ ์๋ฒ ์ก์
(another relatively new React feature)๊ณผ ํจ๊ป ์๋ํฉ๋๋ค. ์๋ฒ ์ก์
์ ๊ฐ๋ฆฌํค๋ action์ด ์๋ ํผ์ด ์ ์ถ๋๋ฉด, experimental_useFormStatus๋ ํด๋น ์ ์ถ์ ํ์ฌ ์ํ์ ๋ํ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
๊ตฌ์ฒด์ ์ผ๋ก, ์ด ํ ์ ๋ค์ ์์ฑ์ ํฌํจํ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค:
pending: ํผ ์ ์ถ์ด ํ์ฌ ์งํ ์ค์ธ์ง ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ ๋ถ๋ฆฌ์ธ ๊ฐ์ ๋๋ค.data: ํผ์ ์ํด ์ ์ถ๋ ๋ฐ์ดํฐ์ ๋๋ค.method: ํผ ์ ์ถ์ ์ฌ์ฉ๋ HTTP ๋ฉ์๋(์: "POST", "GET")์ ๋๋ค.action: ํผ ์ ์ถ์ ์ํด ํธ๋ฆฌ๊ฑฐ๋ ์๋ฒ ์ก์ ์ ๋๋ค.error: ํผ ์ ์ถ์ด ์คํจํ ๊ฒฝ์ฐ์ ์ค๋ฅ ๊ฐ์ฒด์ ๋๋ค. ์ด ๊ฐ์ฒด๋ ์๋ฒ์์ ๋ฐ์ํ ์ค๋ฅ์ ๋ํ ์ ๋ณด๋ฅผ ํฌํจํฉ๋๋ค.
experimental_useFormStatus ์ฌ์ฉ ๋ฐฉ๋ฒ
experimental_useFormStatus๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช
ํ๊ธฐ ์ํด ์ค์ ์ ์ธ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฆ, ์ด๋ฉ์ผ, ๋ฉ์์ง ํ๋๊ฐ ์๋ ๊ฐ๋จํ ์ฐ๋ฝ์ฒ ํผ์ ๋ง๋ค๊ณ , ์ด ํ
์ ์ฌ์ฉํ์ฌ ๋ก๋ฉ ํ์๊ธฐ์ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํ๋ ๋ฐฉ๋ฒ์ ์์ฐํ ๊ฒ์
๋๋ค.
์ ์ ์กฐ๊ฑด
์์ํ๊ธฐ ์ ์ React ํ๋ก์ ํธ๊ฐ ์ค์ ๋์ด ์๊ณ ์คํ์ ๊ธฐ๋ฅ์ ์ง์ํ๋ React ๋ฒ์ ์ ์ฌ์ฉํ๊ณ ์๋์ง ํ์ธํ์ธ์. react.config.js ํ์ผ(๋๋ ๋น๋ ๋๊ตฌ์ ํด๋นํ๋ ์ค์ )์์ ์คํ์ ๊ธฐ๋ฅ์ ํ์ฑํํด์ผ ํ ์๋ ์์ต๋๋ค. ๋ํ ํผ ์ ์ถ์ ์ฒ๋ฆฌํ๊ณ ์ ์ ํ ์๋ต์ ๋ฐํํ๋๋ก ๊ตฌ์ฑ๋ ๋ฐฑ์๋(์: Node.js์ Express)๊ฐ ์๋์ง ํ์ธํ์ธ์.
์์ : ์ฐ๋ฝ์ฒ ํผ
๋ค์์ React ์ปดํฌ๋ํธ ์ฝ๋์ ๋๋ค:
import React, { useState } from 'react';
import { experimental_useFormStatus as useFormStatus } from 'react-dom';
async function handleSubmit(formData) {
'use server';
try {
const response = await fetch('/api/contact', {
method: 'POST',
body: formData,
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'ํผ ์ ์ถ์ ์คํจํ์ต๋๋ค');
}
// ์ฑ๊ณต์ ์ธ ์ ์ถ ์ฒ๋ฆฌ (์: ๋ฆฌ๋๋ ์
, ์ฑ๊ณต ๋ฉ์์ง ํ์)
console.log('ํผ์ด ์ฑ๊ณต์ ์ผ๋ก ์ ์ถ๋์์ต๋๋ค!');
// ์ค์ ์ ํ๋ฆฌ์ผ์ด์
์์๋ ์ฌ๊ธฐ์ ๋ฆฌ๋๋ ์
ํ๊ฑฐ๋ ์ํ๋ฅผ ์
๋ฐ์ดํธํ ์ ์์ต๋๋ค
return { success: true, message: 'ํผ์ด ์ฑ๊ณต์ ์ผ๋ก ์ ์ถ๋์์ต๋๋ค!' };
} catch (error) {
console.error('ํผ ์ ์ถ ์ค๋ฅ:', error);
return { success: false, message: error.message };
}
}
function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: '',
});
const { pending, data, error } = useFormStatus();
const handleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
return (
);
}
export default ContactForm;
์ค๋ช
useFormStatus๊ฐ์ ธ์ค๊ธฐ:react-dom์์experimental_useFormStatusํ ์ ๊ฐ์ ธ์ต๋๋ค. ์ด๊ฒ์ ์คํ์ ์ธ ๊ธฐ๋ฅ์ด๋ฏ๋ก ํฅํ React ๋ฒ์ ์์๋ ๊ฐ์ ธ์ค๊ธฐ ๊ฒฝ๋ก๊ฐ ๋ณ๊ฒฝ๋ ์ ์์์ ๊ธฐ์ตํ์ธ์.- ํผ ์ํ:
useState๋ฅผ ์ฌ์ฉํ๋ ์ํ ๋ณ์formData๋ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ์ด๋ฆ, ์ด๋ฉ์ผ, ๋ฉ์์ง๋ฅผ ์ถ์ ํฉ๋๋ค. useFormStatusํ : ์ปดํฌ๋ํธ ๋ด์์useFormStatus()๋ฅผ ํธ์ถํฉ๋๋ค. ์ด ํ ์ ํผ์ด ์๋ฒ ์ก์ ์ ํตํด ์ ์ถ๋ ๋ ํผ์ ์ ์ถ ์ํ์ ๋ํ ์ ๋ณด๋ฅผ ์๋์ผ๋ก ์ ๊ณตํฉ๋๋ค.- ์ํ ์์ฑ ์ ๊ทผ:
useFormStatus()๊ฐ ๋ฐํํ๋ ๊ฐ์ฒด์์pending,data,error๋ฅผ ์ถ์ถํฉ๋๋ค. - ๋ก๋ฉ ํ์๊ธฐ:
pending๋ถ๋ฆฌ์ธ ๊ฐ์ ์ฌ์ฉํ์ฌ ์ ์ถ ๋ฒํผ์ ์กฐ๊ฑด๋ถ๋ก "์ ์ถ ์ค..." ๋ฉ์์ง๋ฅผ ๋ ๋๋งํ๊ณ , ์ฌ๋ฌ ๋ฒ ์ ์ถ๋๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ฒํผ์ ๋นํ์ฑํํฉ๋๋ค. - ์ค๋ฅ ์ฒ๋ฆฌ: ํผ ์ ์ถ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด(
error์์ฑ์ผ๋ก ํ์๋จ) ์ฌ์ฉ์์๊ฒ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค. - ์ฑ๊ณต ๋ฉ์์ง: ์ ์ถ์ด ์ฑ๊ณตํ๋ฉด(์๋ฒ ์ก์ ์ด { success: true, message: '...' }๋ฅผ ๋ฐํํ์ฌ ๊ฒฐ์ ๋จ) ์ฑ๊ณต ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค.
- ์๋ฒ ์ก์
:
handleSubmitํจ์๋'use server'๋ก ํ์๋์ด ์๋ฒ ์ก์ ์ด ๋ฉ๋๋ค. ์ด ํจ์๋fetch๋ฅผ ์ฌ์ฉํ์ฌ ํผ ๋ฐ์ดํฐ๋ฅผ API ์๋ํฌ์ธํธ(/api/contact)๋ก ๋ณด๋ ๋๋ค. - ์๋ฒ ์ก์
์์์ ์ค๋ฅ ์ฒ๋ฆฌ: ์๋ฒ ์ก์
์ API ํธ์ถ๊ณผ ์ ์ฌ์ ์ธ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๋ ค๊ณ ์๋ํฉ๋๋ค. API ์๋ต์ ์ค๋ฅ๊ฐ ์๊ฑฐ๋ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด
{ success: false, message: '...' }๋ฅผ ๋ฐํํฉ๋๋ค. ์ด ๋ฉ์์ง๋useFormStatusํ ์error์์ฑ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. - Action ์์ฑ:
<form>ํ๊ทธ์action์์ฑ์handleSubmit์๋ฒ ์ก์ ์ผ๋ก ์ค์ ๋ฉ๋๋ค. ์ด๋ React์๊ฒ ํผ์ด ์ ์ถ๋ ๋ ์ด ํจ์๋ฅผ ์ฌ์ฉํ๋๋ก ์ง์ํฉ๋๋ค.
๋ฐฑ์๋ (Node.js์ Express๋ฅผ ์ฌ์ฉํ ๋จ์ํ๋ ์์ )
๋ค์์ Express๋ฅผ ์ฌ์ฉํ๋ Node.js ์๋ฒ์ ๋งค์ฐ ๊ธฐ๋ณธ์ ์ธ ์์ ๋ก, ํผ ์ ์ถ์ ์ฒ๋ฆฌํฉ๋๋ค:
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
const port = 3001;
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.post('/api/contact', (req, res) => {
const { name, email, message } = req.body;
// ์๋ฒ ์ธก ์ ํจ์ฑ ๊ฒ์ฌ ๋๋ ์ฒ๋ฆฌ ์๋ฎฌ๋ ์ด์
(์: ์ด๋ฉ์ผ ์ ์ก)
if (!name || !email || !message) {
return res.status(400).json({ message: '๋ชจ๋ ํ๋๋ ํ์์
๋๋ค.' });
}
if (!email.includes('@')) {
return res.status(400).json({message: '์ ํจํ์ง ์์ ์ด๋ฉ์ผ ํ์์
๋๋ค.'});
}
// ์ง์ฐ ์๊ฐ์ ๋๊ณ ์ฑ๊ณต์ ์ธ ์์
์๋ฎฌ๋ ์ด์
setTimeout(() => {
console.log('ํผ ๋ฐ์ดํฐ ์์ :', { name, email, message });
res.status(200).json({ message: 'ํผ์ด ์ฑ๊ณต์ ์ผ๋ก ์ ์ถ๋์์ต๋๋ค!' });
}, 1000);
});
app.listen(port, () => {
console.log(`์๋ฒ๊ฐ http://localhost:${port}์์ ์์ ๋๊ธฐ ์ค์
๋๋ค`);
});
๋ฐฑ์๋์ ์ฃผ์ ๊ณ ๋ ค ์ฌํญ:
- ์ ํจ์ฑ ๊ฒ์ฌ: ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ๊ณผ ๋ณด์์ ๋ณด์ฅํ๊ธฐ ์ํด ํญ์ ์๋ฒ ์ธก ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ํํ์ธ์.
- ์ค๋ฅ ์ฒ๋ฆฌ: ์๊ธฐ์น ์์ ๋ฌธ์ ๋ฅผ ํฌ์ฐฉํ๊ณ ํด๋ผ์ด์ธํธ์ ์๋ฏธ ์๋ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ๋ฐํํ๊ธฐ ์ํด ๊ฒฌ๊ณ ํ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ๊ตฌํํ์ธ์.
- ๋ณด์: ๊ต์ฐจ ์ฌ์ดํธ ์คํฌ๋ฆฝํ (XSS) ๋ฐ SQL ์ธ์ ์ ๊ณผ ๊ฐ์ ๋ณด์ ์ทจ์ฝ์ ์ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ชจ๋ ์ ๋ ฅ ๋ฐ์ดํฐ๋ฅผ ์ ์ ํ๊ณ ์ ํจ์ฑ์ ๊ฒ์ฌํ์ธ์.
- CORS: React ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ฉ์ธ์์ ์ค๋ ์์ฒญ์ ํ์ฉํ๋๋ก ๊ต์ฐจ ์ถ์ฒ ๋ฆฌ์์ค ๊ณต์ (CORS)๋ฅผ ์ ์ ํ๊ฒ ๊ตฌ์ฑํ์ธ์.
- JSON ์๋ต: ์ ์ ํ HTTP ์ํ ์ฝ๋(์: ์ฑ๊ณต ์ 200, ํด๋ผ์ด์ธํธ ์ค๋ฅ ์ 400, ์๋ฒ ์ค๋ฅ ์ 500)์ ํจ๊ป JSON ์๋ต์ ํด๋ผ์ด์ธํธ์ ๋ฐํํ์ธ์.
experimental_useFormStatus ์ฌ์ฉ์ ์ด์
- ๋จ์ํ๋ ํผ ๊ด๋ฆฌ: ํผ ์ ์ถ ์ํ์ ์ค์ ์ง์ค ๊ด๋ฆฌ๋ ์์ฉ๊ตฌ ์ฝ๋๋ฅผ ์ค์ด๊ณ ์ฝ๋ ๊ฐ๋ ์ฑ์ ํฅ์์ํต๋๋ค.
- ํฅ์๋ ์ฌ์ฉ์ ๊ฒฝํ: ํผ ์ ์ถ ์ํ์ ๋ํ ์ค์๊ฐ ํผ๋๋ฐฑ(๋ก๋ฉ ํ์๊ธฐ, ์ค๋ฅ ๋ฉ์์ง)์ ์ฌ์ฉ์ ์ฐธ์ฌ๋ฅผ ๋์ด๊ณ ๋ถํธํจ์ ์ค์ ๋๋ค.
- ๊ฐํ๋ ์ค๋ฅ ์ฒ๋ฆฌ: ์์ธํ ์ค๋ฅ ์ ๋ณด์ ๋ ์ฝ๊ฒ ์ ๊ทผํ ์ ์์ด ๋ณด๋ค ๋์ํ๋ ์ค๋ฅ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๊ณ ๋๋ฒ๊น ์ด ๊ฐ์ ๋ฉ๋๋ค.
- ์ ์ธ์ ์ ๊ทผ ๋ฐฉ์: ์ด ํ ์ ํผ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ์ ์ธ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ฌ ์ฝ๋๋ฅผ ๋ ์์ธก ๊ฐ๋ฅํ๊ณ ์ถ๋ก ํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
- ์๋ฒ ์ก์ ๊ณผ์ ํตํฉ: React ์๋ฒ ์ก์ ๊ณผ์ ์ํํ ํตํฉ์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ๋ฐ ๋ณ๊ฒฝ์ ๋จ์ํํ์ฌ ๋ ํจ์จ์ ์ด๊ณ ์ฑ๋ฅ์ด ๋ฐ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ญ๋๋ค.
๊ณ ๊ธ ์ฌ์ฉ ์ฌ๋ก
๊ธฐ๋ณธ์ ์ธ ์์ ๋ฅผ ๋์ด, experimental_useFormStatus๋ ๋ ๋ณต์กํ ์๋๋ฆฌ์ค์์๋ ์ฌ์ฉ๋ ์ ์์ต๋๋ค:
1. ํ ํ์ด์ง์์ ์ฌ๋ฌ ํผ ์ฒ๋ฆฌํ๊ธฐ
ํ ํ์ด์ง์ ์ฌ๋ฌ ํผ์ด ์๋ ๊ฒฝ์ฐ ๊ฐ ํผ์ ์์ฒด useFormStatus ์ธ์คํด์ค๋ฅผ ๊ฐ์ง๋ฏ๋ก ์ ์ถ ์ํ๋ฅผ ๋
๋ฆฝ์ ์ผ๋ก ์ถ์ ํ ์ ์์ต๋๋ค.
2. ์ฌ์ฉ์ ์ ์ ์ ํจ์ฑ ๊ฒ์ฌ ๋ก์ง ๊ตฌํํ๊ธฐ
useFormStatus๋ฅผ ์ฌ์ฉ์ ์ ์ ์ ํจ์ฑ ๊ฒ์ฌ ๋ก์ง๊ณผ ํตํฉํ์ฌ ์ ํจ์ฑ ๊ฒ์ฌ ์ค๋ฅ๋ฅผ ์ค์๊ฐ์ผ๋ก ํ์ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, Yup ๋๋ Zod์ ๊ฐ์ ์ ํจ์ฑ ๊ฒ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ์๋ฒ์ ์ ์ถํ๊ธฐ ์ ์ ํด๋ผ์ด์ธํธ ์ธก์์ ํผ ๋ฐ์ดํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฌํ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ์๋ฒ ์ก์
์ useFormStatus๋ฅผ ์ฌ์ฉํ์ฌ ํ์ํ ์ ์๋ ๋ฐฑ์๋ ๊ท์น์ ๊ธฐ๋ฐํ ์ ํจ์ฑ ๊ฒ์ฌ ์ค๋ฅ๋ฅผ ๋ฐํํ ์ ์์ต๋๋ค.
3. ๋๊ด์ ์ ๋ฐ์ดํธ (Optimistic Updates)
useFormStatus๋ฅผ ์ฌ์ฉํ์ฌ ๋๊ด์ ์
๋ฐ์ดํธ๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค. ์ด๋ ์ฌ์ฉ์๊ฐ ํผ์ ์ ์ถํ ์งํ์ ์ ์ถ์ด ์ฑ๊ณตํ ๊ฒ์ด๋ผ๊ณ ๊ฐ์ ํ๊ณ UI๋ฅผ ์ฆ์ ์
๋ฐ์ดํธํ๋ ๋ฐฉ์์
๋๋ค. ์ ์ถ์ด ์คํจํ๋ฉด UI๋ฅผ ์ด์ ์ํ๋ก ๋๋๋ฆฌ๊ณ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํ ์ ์์ต๋๋ค.
4. ํ์ผ ์ ๋ก๋๋ฅผ ์ํ ์งํ๋ฅ ํ์๊ธฐ
useFormStatus๊ฐ ํ์ผ ์
๋ก๋์ ๋ํ ์งํ ์ํฉ ์
๋ฐ์ดํธ๋ฅผ ์ง์ ์ ๊ณตํ์ง๋ ์์ง๋ง, ๋ค๋ฅธ ๊ธฐ์ (์: XMLHttpRequest ๊ฐ์ฒด์ ๊ทธ upload.onprogress ์ด๋ฒคํธ ์ฌ์ฉ)๊ณผ ๊ฒฐํฉํ์ฌ ์ฌ์ฉ์์๊ฒ ์งํ๋ฅ ํ์๊ธฐ๋ฅผ ํ์ํ ์ ์์ต๋๋ค.
ํํ ํจ์ ๊ณผ ์ด๋ฅผ ํผํ๋ ๋ฐฉ๋ฒ
- ์๋ฒ ์ก์
์ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ:
experimental_useFormStatus๋ ์ฃผ๋ก React ์๋ฒ ์ก์ ๊ณผ ํจ๊ป ์๋ํ๋๋ก ์ค๊ณ๋์์ต๋๋ค. ์๋ฒ ์ก์ ์ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ, ํผ ์ ์ถ ์ํ๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌํ๊ณ ๊ทธ์ ๋ฐ๋ผ UI๋ฅผ ์ ๋ฐ์ดํธํด์ผ ํ๋ฉฐ, ์ด๋ ์ด ํ ์ ์ฌ์ฉํ๋ ๋ชฉ์ ์ ๋ฌด์๋ฏธํ๊ฒ ๋ง๋ญ๋๋ค. - ์๋ฒ์์์ ๋ถ์ ํํ ์ค๋ฅ ์ฒ๋ฆฌ: ์๋ฒ ์ธก ์ฝ๋๊ฐ ์ค๋ฅ๋ฅผ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌํ๊ณ ํด๋ผ์ด์ธํธ์ ์๋ฏธ ์๋ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ๋ฐํํ๋์ง ํ์ธํ์ธ์.
useFormStatusํ ์error์์ฑ์ ์๋ฒ์์ ๋ฐ์ํ ์ค๋ฅ์ ๋ํ ์ ๋ณด๋ง ํฌํจํฉ๋๋ค. - ์ ์ฌ์ ์ธ ๋ณด์ ์ทจ์ฝ์ ๋ฌด์: ๋ณด์ ์ทจ์ฝ์ ์ ๋ฐฉ์งํ๊ธฐ ์ํด ํญ์ ํด๋ผ์ด์ธํธ ์ธก๊ณผ ์๋ฒ ์ธก ๋ชจ๋์์ ์ฌ์ฉ์ ์ ๋ ฅ์ ์ ์ ํ๊ณ ์ ํจ์ฑ์ ๊ฒ์ฌํ์ธ์.
- ์ฌ์ฉ์์๊ฒ ํผ๋๋ฐฑ์ ์ ๊ณตํ์ง ์๋ ๊ฒฝ์ฐ: ์ฌ์ฉ์์๊ฒ ํผ ์ ์ถ ์ํ(๋ก๋ฉ ํ์๊ธฐ, ์ค๋ฅ ๋ฉ์์ง, ์ฑ๊ณต ๋ฉ์์ง)์ ๋ํ ๋ช ํํ๊ณ ์๊ธฐ์ ์ ํ ํผ๋๋ฐฑ์ ์ ๊ณตํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด๋ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๊ณ ๋ถํธํจ์ ์ค์ ๋๋ค.
experimental_useFormStatus ์ฌ์ฉ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
- ์๋ฏธ ์๋ ์ค๋ฅ ๋ฉ์์ง ์ฌ์ฉ: ์ฌ์ฉ์๊ฐ ๋ฌด์์ด ์๋ชป๋์๋์ง, ์ด๋ป๊ฒ ์์ ํด์ผ ํ๋์ง ์ดํดํ๋ ๋ฐ ๋์์ด ๋๋ ๋ช ํํ๊ณ ๊ฐ๊ฒฐํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ ๊ณตํ์ธ์.
- ํด๋ผ์ด์ธํธ ์ธก ์ ํจ์ฑ ๊ฒ์ฌ ๊ตฌํ: ๋ถํ์ํ ์๋ฒ ์์ฒญ์ ์ค์ด๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๊ธฐ ์ํด ์๋ฒ์ ์ ์ถํ๊ธฐ ์ ์ ํด๋ผ์ด์ธํธ ์ธก์์ ํผ ๋ฐ์ดํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฌํ์ธ์.
- ์ค๋ฅ๋ฅผ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ: ์๊ธฐ์น ์์ ๋ฌธ์ ๋ฅผ ํฌ์ฐฉํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ถฉ๋ํ๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํด ๊ฒฌ๊ณ ํ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ๊ตฌํํ์ธ์.
- ํผ์ ์ฒ ์ ํ ํ ์คํธํ๊ธฐ: ๋ค์ํ ์ ๋ ฅ๊ณผ ์๋๋ฆฌ์ค๋ก ํผ์ ํ ์คํธํ์ฌ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๊ณ ์ค๋ฅ ์ฒ๋ฆฌ๊ฐ ์์๋๋ก ์๋ํ๋์ง ํ์ธํ์ธ์.
- ์ฝ๋๋ฅผ ๊นจ๋ํ๊ณ ์ฝ๊ธฐ ์ฝ๊ฒ ์ ์งํ๊ธฐ: ์ฝ๋๋ฅผ ๋ ์ฝ๊ฒ ์ดํดํ๊ณ ์ ์ง ๊ด๋ฆฌํ ์ ์๋๋ก ์ค๋ช ์ ์ธ ๋ณ์ ์ด๋ฆ๊ณผ ์ฃผ์์ ์ฌ์ฉํ์ธ์.
- ์ ๊ทผ์ฑ ์ฐ์ ์ํ๊ธฐ: ์ฅ์ ๊ฐ ์๋ ์ฌ์ฉ์๋ฅผ ํฌํจํ ๋ชจ๋ ์ฌ์ฉ์๊ฐ ํผ์ ์ ๊ทผํ ์ ์๋๋ก ํ์ธ์. ์๋งจํฑ HTML์ ์ฌ์ฉํ๊ณ , ํผ ํ๋์ ์ ์ ํ ๋ ์ด๋ธ์ ์ ๊ณตํ๋ฉฐ, ์ค๋ฅ ๋ฉ์์ง๊ฐ ๋ช ํํ๊ฒ ๋ณด์ด๊ณ ์ดํดํ ์ ์๋๋ก ํ์ธ์.
๊ตญ์ ํ ๊ณ ๋ ค ์ฌํญ
์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ์ํ ํผ์ ๊ตฌ์ถํ ๋ ๋ค์๊ณผ ๊ฐ์ ๊ตญ์ ํ ์ธก๋ฉด์ ๊ณ ๋ คํ์ธ์:
- ์ค๋ฅ ๋ฉ์์ง์ ํ์งํ: ์ค๋ฅ ๋ฉ์์ง๊ฐ ์ฌ์ฉ์์ ์ ํธ ์ธ์ด๋ก ๋ฒ์ญ๋์๋์ง ํ์ธํ์ธ์.
i18next์ ๊ฐ์ ํ์งํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฒ์ญ์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค. - ๋ ์ง ๋ฐ ์ซ์ ์์: ์ฌ์ฉ์์ ๋ก์ผ์ผ์ ๋ฐ๋ผ ์ ์ ํ ๋ ์ง ๋ฐ ์ซ์ ์์์ ์ฌ์ฉํ์ธ์.
- ์ฃผ์ ํ์: ๋ค๋ฅธ ๊ตญ๊ฐ์ ์ฃผ์ ํ์์ ๋ง๊ฒ ์ฃผ์ ํผ ํ๋๋ฅผ ์กฐ์ ํ์ธ์. ์๋ฅผ ๋ค์ด, ์ผ๋ถ ๊ตญ๊ฐ๋ ๋์ ์ด๋ฆ ์์ ์ฐํธ๋ฒํธ๋ฅผ ์ฌ์ฉํ๊ณ , ๋ค๋ฅธ ๊ตญ๊ฐ๋ ๋ค์ ์ฌ์ฉํฉ๋๋ค.
- ์ ํ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ: ๋ค๋ฅธ ๊ตญ๊ฐ ์ฝ๋ ๋ฐ ์ ํ๋ฒํธ ํ์์ ์ง์ํ๋ ์ ํ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๊ตฌํํ์ธ์.
- ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ(RTL) ๋ ์ด์์: ์๋์ด ๋ฐ ํ๋ธ๋ฆฌ์ด์ ๊ฐ์ ์ธ์ด๋ฅผ ์ํด RTL ๋ ์ด์์์ ์ง์ํ์ธ์.
์๋ฅผ ๋ค์ด, ์ ํ๋ฒํธ๋ฅผ ๋ฌป๋ ํผ์ ์ฌ์ฉ์๊ฐ ์ ํํ ๊ตญ๊ฐ์ ๋ฐ๋ผ ์ ํจ์ฑ ๊ฒ์ฌ ๊ท์น์ ๋์ ์ผ๋ก ์กฐ์ ํด์ผ ํฉ๋๋ค. ๋ฏธ๊ตญ ์ ํ๋ฒํธ๋ 10์๋ฆฌ ์ซ์๊ฐ ํ์ํ์ง๋ง, ์๊ตญ ์ ํ๋ฒํธ๋ ๋งจ ์์ 0์ ํฌํจํ์ฌ 11์๋ฆฌ๊ฐ ํ์ํ ์ ์์ต๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก "์ ํจํ์ง ์์ ์ ํ๋ฒํธ ํ์์ ๋๋ค"์ ๊ฐ์ ์ค๋ฅ ๋ฉ์์ง๋ ์ฌ์ฉ์์ ์ธ์ด๋ก ๋ฒ์ญ๋์ด์ผ ํฉ๋๋ค.
๊ฒฐ๋ก
experimental_useFormStatus๋ React์ ํดํท์ ์ถ๊ฐ๋ ๊ฐ์น ์๋ ๊ธฐ๋ฅ์ผ๋ก, ํผ ์ ์ถ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฐ์ํ๋๊ณ ์ ์ธ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์ด ํ
์ ํ์ฉํจ์ผ๋ก์จ ๊ฐ๋ฐ์๋ค์ ๋ ๊ฒฌ๊ณ ํ๊ณ ์ฌ์ฉ์ ์นํ์ ์ด๋ฉฐ ์ ์ง ๊ด๋ฆฌ๊ฐ ์ฉ์ดํ ํผ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ์ด ๊ธฐ๋ฅ์ ํ์ฌ ์คํ ๋จ๊ณ์ด๋ฏ๋ก ์ต์ React ๋ฌธ์ ๋ฐ ์ปค๋ฎค๋ํฐ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ณ์ ์ฃผ์ํด์ผ ํฉ๋๋ค. ์ด ๊ฐ๋ ฅํ ๋๊ตฌ๋ฅผ ๋ฐ์๋ค์ฌ ํผ ์ฒ๋ฆฌ ๋ฅ๋ ฅ์ ํฅ์์ํค๊ณ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ฐ์ด๋ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ง๋ค์ด๋ณด์ธ์.