یک فرم React ممکن است در حالت عادی درست کار کند، اما با دوبار کلیک، پاسخ کند یا داده نامعتبر دچار ابهام شود. مدیریت حرفهای فرم از انتخاب کتابخانه شروع نمیشود. ابتدا باید بدانید چه دادهای میخواهید، چه چیزی در مرورگر بررسی میشود و نتیجه ارسال چگونه به کاربر میرسد. فرم، قرارداد میان رابط و سرور است. State و Hook ابزار اجرای این قراردادند، نه جایگزین آن. برای فرم کوچک، امکانات مرورگر و React اغلب کافیاند؛ پیچیدگی را زمانی اضافه کنید که مسئله مشخصی را حل کند.
ساختار HTML هنوز پایه فرم است
هر ورودی به Label، نام و نوع مناسب نیاز دارد. Label قابل مشاهده باید پس از تایپ هم باقی بماند؛ Placeholder جای آن نیست. ویژگی name تعیین میکند داده هنگام خواندن FormData با چه کلیدی در دسترس باشد. دکمه ارسال را با type مشخص کنید و دکمه کمکی داخل فرم را ناخواسته Submit نکنید. استفاده از عنصر form، رفتار صفحهکلید و ارسال با Enter را قابل پیشبینیتر میکند. React دلیل کنار گذاشتن این قراردادهای وب نیست.
در طراحی فرم وب، مقدار اطلاعات و ترتیب سؤالها اهمیت دارند. توسعهدهنده نیز باید بداند فیلد چرا وجود دارد و کدام مورد اختیاری است. اطلاعاتی که برای انجام کار لازم نیست، به فرم اضافه نکنید. برای داده حساس، محل ذخیره و دسترسی باید روشن باشد. ظاهر زیبا، مشکل جمعآوری بیدلیل یا قرارداد مبهم را حل نمیکند. پیام راهنما نیز باید با قاعده واقعی سیستم سازگار باشد.
Controlled و Uncontrolled را درست انتخاب کنید
در ورودی Controlled، مقدار از State میآید و رویداد تغییر باید آن را بهروز کند. در Uncontrolled، مرورگر مقدار جاری را نگه میدارد و میتوانید هنگام ارسال با FormData آن را بخوانید. هیچکدام برای همه فرمها بهترین نیستند. اگر نمایش زنده به مقدار وابسته است، کنترل مقدار ممکن است مفید باشد. اگر فقط در ارسال داده را میخواهید، State جدا برای هر حرف الزام ندارد. انتخاب باید به رفتار مورد نیاز مربوط باشد.
مستند input در React توضیح میدهد که ورودی Controlled نباید از مقدار تعریفنشده به رشته تغییر کند و به بهروزرسانی همزمان در onChange نیاز دارد. برای مقدار متنی اولیه، رشته خالی معمولاً انتخاب روشنتری از undefined است. defaultValue فقط مقدار اولیه را تعیین میکند، نه اینکه مقدار جاری را مانند value کنترل کند. اگر این تفاوت روشن نباشد، فرم ممکن است هنگام تغییر داده اولیه رفتار نامنتظره داشته باشد.
اعتبارسنجی مرورگر و سرور
required و نوع email به کاربر برای اصلاح سریع ورودی کمک میکنند. این بررسی امنیت سرور نیست و قابل دور زدن است. سرور باید نوع، طول، محدوده و اختیار انجام عملیات را مستقل بررسی کند. قاعده سمت کاربر را با سرور هماهنگ نگه دارید، ولی منبع معتبر تصمیم نهایی را مشخص کنید. برای نام یا متن، قواعد فرهنگی و زبانهای مختلف را در نظر بگیرید؛ محدود کردن بیدلیل حروف ممکن است کاربر واقعی را کنار بگذارد.
خطای یک فیلد با خطای سرویس فرق دارد. اگر ایمیل از نظر قالب نامعتبر است، همان فیلد را توضیح دهید. اگر سرویس در دسترس نیست، نگویید کاربر اطلاعات غلط وارد کرده است. پاسخ نامعلوم نیز با شکست قطعی یکسان نیست، بهویژه در پرداخت. متن UX Writing باید دقیقاً همان وضعیتی را بیان کند که سیستم میداند. پیام موفقیت نباید پیش از تأیید واقعی عملیات نمایش داده شود.
نمونه کامل: پیشنمایش درخواست تماس
این نمونه آموزشی فقط اطلاعات را در همان صفحه پیشنمایش میدهد و هیچ درخواستی به سرور نمیفرستد. بنابراین پیام آن از «ثبت درخواست» یا «ذخیره امن» استفاده نمیکند. Node.js نسخه ۲۲٫۱۲ یا جدیدتر و npm لازم است. یک پوشه خالی بسازید و سه فایل زیر را با همین نامها در ریشه آن قرار دهید. این مثال به API، کلید، فایل CSS یا Component دیگری وابسته نیست. نسخههای اصلی وابستگیها در package.json مشخصاند تا محیط آموزشی روشن باشد.
فایل package.json
{"private":true,"type":"module","scripts":{"dev":"vite --host 127.0.0.1"},"dependencies":{"react":"^19.0.0","react-dom":"^19.0.0"},"devDependencies":{"vite":"^7.0.0"}}
فایل index.html
<!doctype html>
<html lang="fa" dir="rtl"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>پیشنمایش فرم</title></head><body><div id="root"></div><script type="module" src="/main.jsx"></script></body></html>
فایل main.jsx
import React, { useState } from 'react';
import { createRoot } from 'react-dom/client';
function App() {
const [preview, setPreview] = useState(null);
const [error, setError] = useState('');
function handleSubmit(event) {
event.preventDefault();
const data = new FormData(event.currentTarget);
const name = String(data.get('name') ?? '').trim();
const email = String(data.get('email') ?? '').trim();
if (!name) {
setPreview(null);
setError('نام را وارد کنید؛ مقدار فقط شامل فاصله پذیرفته نیست.');
return;
}
setError('');
setPreview({ name, email });
}
return <main>
<h1>پیشنمایش درخواست تماس</h1>
<p>نمونه آموزشی؛ هیچ اطلاعاتی به سرور ارسال نمیشود.</p>
<form onSubmit={handleSubmit} onReset={() => { setPreview(null); setError(''); }}>
<p><label htmlFor="name">نام</label><br />
<input id="name" name="name" required maxLength={80} autoComplete="name" aria-describedby="name-error" aria-invalid={Boolean(error)} /></p>
<p id="name-error" role="alert">{error}</p>
<p><label htmlFor="email">ایمیل</label><br />
<input id="email" name="email" type="email" dir="ltr" required maxLength={254} autoComplete="email" /></p>
<button type="submit">نمایش پیشنمایش</button>{' '}
<button type="reset">بازنشانی</button>
</form>
<section aria-live="polite" aria-label="نتیجه پیشنمایش">
{preview && <><h2>داده خواندهشده از فرم</h2><p>نام: {preview.name}</p><p>ایمیل: <bdi>{preview.email}</bdi></p><p>این داده فقط در حافظه همین صفحه است.</p></>}
</section>
</main>;
}
createRoot(document.getElementById('root')).render(<App />);
در همان پوشه، ابتدا npm install و سپس npm run dev را اجرا کنید. نشانی محلی نمایشدادهشده توسط Vite را باز کنید. انتظار میرود فرم نام و ایمیل دیده شود؛ ورودی لازم یا ایمیل نامعتبر با رفتار مرورگر متوقف میشود و ورودی معتبر در بخش پیشنمایش میآید. این دستورها برای اجرای خوانندهاند؛ مقاله ادعای انجام آزمون اجرایی در محیط انتشار ندارد. توقف سرور محلی با Ctrl+C انجام میشود. برای پاک کردن پیشنمایش، دکمه بازنشانی را بزنید.
چرا نمونه از FormData استفاده میکند؟
در این فرم، مقدارها فقط هنگام ارسال لازماند. FormData از خود فرم خوانده میشود و برای هر تغییر ورودی State نداریم. State فقط خروجی پیشنمایش را نگه میدارد. این جداسازی، تفاوت داده در حال ورود و نتیجه خواندهشده را نشان میدهد. متن نام پس از حذف فاصله ابتدا و انتها بررسی میشود؛ اگر خالی باشد، پیام مشخصی نمایش داده میشود. React متن را به شکل معمول رندر میکند و از تزریق HTML خام استفاده نشده است.
با تغییر فرم پس از پیشنمایش، خروجی قبلی همان داده خواندهشده باقی میماند. این رفتار عمدی است و نباید آن را داده ذخیرهشده حساب کرد. در محصول واقعی، باید مشخص کنید پس از ویرایش، نتیجه قبلی پنهان یا بهعنوان نسخه قدیمی علامتگذاری شود. نمونه کوچک قرار نیست تمام رفتارهای محصول را پنهانی ادعا کند. برای فرم واقعی، وضعیت ارسال، پاسخ سرور و سیاست نگهداری داده باید جدا طراحی شوند.
وضعیت ارسال و دوبارهکاری
در ارتباط واقعی، حالتهای آماده، در حال ارسال، موفق و ناموفق را مشخص کنید. جلوگیری از کلیک تکراری در رابط مفید است، اما سرور نیز باید عملیات حساس را در برابر تکرار مدیریت کند. غیرفعال شدن دکمه، تضمین یکبار اجرا شدن نیست. درخواست میتواند با قطع اتصال یا تکرار شبکه دوباره برسد. برای عملیات مالی یا ساخت رکورد مهم، قرارداد جلوگیری از اثر تکراری باید در سمت معتبر سیستم تعریف شود.
وقتی ارسال ناموفق است، داده را بیدلیل پاک نکنید. وقتی نتیجه نامعلوم است، مسیر پیگیری بدهید. اگر پاسخ دیر میرسد و کاربر فرم را تغییر داده، روشن کنید پاسخ به کدام نسخه مربوط است. مدیریت درخواست قدیمی و تغییر صفحه، بخشی از طراحی ارتباط است. Stateهای زیاد و مستقل ممکن است ترکیبهای ناممکن بسازند؛ مثلاً هم موفق و هم در حال ارسال. وضعیتها را طوری مدل کنید که معنای هر ترکیب روشن باشد.
کتابخانه چه زمانی کمک میکند؟
فرم چندمرحلهای، فیلدهای تکرارشونده، قواعد وابسته و خطاهای پیچیده ممکن است ابزار مدیریت فرم را توجیه کنند. پیش از انتخاب، نیاز واقعی، اندازه پروژه و شیوه اتصال به Componentهای موجود را بررسی کنید. نام کتابخانه، قواعد دامنه یا امنیت را خودکار درست نمیکند. اعتبارسنجی Schema نیز باید با قرارداد سرور سازگار باشد. در راهنمای Zod، بررسی داده زمان اجرا از نوعهای TypeScript جداست؛ این تفاوت برای فرم اهمیت دارد.
برای فرم ساده، نصب چند وابستگی فقط برای خواندن دو مقدار شاید هزینه نگهداری بیشتری ایجاد کند. از طرف دیگر، بازنویسی دستی قابلیتهای پیچیده هم همیشه صرفه ندارد. انتخاب را با مسئله بنویسید: چه چیزی سخت شده و ابزار کدام بخش را ساده میکند؟ بعد، وابستگی و محدودیت را در مستند پروژه ثبت کنید. این تصمیم باید با تجربه تیم و نیاز کاربر سازگار باشد، نه صرفاً با محبوبیت یک روش.
دسترسپذیری و تحویل قابل نگهداری
فرم را با ترتیب منطقی، Label و پیام مرتبط بسازید. خطا فقط با رنگ اعلام نشود. برای نتیجه پویا، روش اعلام وضعیت به فناوری کمکی را در نظر بگیرید. اگر خطاهای متعدد وجود دارند، خلاصه و امکان رفتن به فیلد کمک میکند. نمایش RTL و متن مختلط را با محتوا واقعی طراحی کنید؛ شماره و نشانی ممکن است جهت متفاوت داشته باشند. نام فیلد و پیام باید از واژههای ثابت محصول استفاده کنند.
در پایان، قرارداد داده، وضعیتها و محدودیتها را همراه کد تحویل دهید. اگر نمونه فقط پیشنمایش است، آن را محصول آماده ثبت اطلاعات معرفی نکنید. فرم حرفهای به معنی بیشترین تعداد Hook یا کتابخانه نیست. کاربر باید بداند چه اطلاعاتی خواسته میشود، خطا را چگونه اصلاح کند و نتیجه عمل چیست. توسعهدهنده بعدی نیز باید بفهمد داده از کجا میآید، کجا معتبر میشود و کدام رفتار هنوز به پیادهسازی نیاز دارد.
هنوز دیدگاهی ثبت نشده
اولین نفری باشید که نظر میدهد!