สำรวจ hook useFormStatus ของ React เพื่อการจัดการฟอร์มที่ง่ายขึ้น: สถานะการส่ง, การจัดการข้อผิดพลาด, และประสบการณ์ผู้ใช้ที่ดีขึ้น พร้อมตัวอย่างและแนวทางปฏิบัติที่ดีที่สุด
React useFormStatus: คู่มือฉบับสมบูรณ์สำหรับการจัดการสถานะของฟอร์ม
hook useFormStatus ซึ่งเปิดตัวใน React 18 เป็นวิธีที่ทรงพลังและมีประสิทธิภาพในการจัดการสถานะการส่งฟอร์มภายใน React Server Components hook นี้ถูกออกแบบมาโดยเฉพาะเพื่อทำงานกับ server actions ทำให้มีการผสานรวมที่ราบรื่นสำหรับการจัดการการส่งฟอร์มโดยตรงบนเซิร์ฟเวอร์ มันช่วยลดความซับซ้อนของกระบวนการติดตามสถานะการส่งฟอร์ม โดยให้ข้อมูลที่มีค่า เช่น ฟอร์มกำลังรอการดำเนินการ (pending) สำเร็จ หรือพบข้อผิดพลาด คู่มือนี้จะสำรวจความสามารถของ useFormStatus ประโยชน์ของมัน และตัวอย่างการใช้งานจริงในสถานการณ์ต่างๆ
ทำความเข้าใจ Server Actions และ useFormStatus
ก่อนที่จะลงลึกใน useFormStatus สิ่งสำคัญคือต้องเข้าใจ React Server Components และ Server Actions ก่อน Server Actions ช่วยให้คุณสามารถกำหนดฟังก์ชันที่ทำงานบนเซิร์ฟเวอร์ ซึ่งสามารถเข้าถึงได้โดยตรงจากคอมโพเนนต์ React ของคุณ สิ่งนี้ทำให้สามารถจัดการการส่งฟอร์ม การดึงข้อมูล และการดำเนินการฝั่งเซิร์ฟเวอร์อื่นๆ ได้โดยไม่จำเป็นต้องมี API endpoint แยกต่างหาก
จากนั้น hook useFormStatus จะให้ข้อมูลเชิงลึกเกี่ยวกับการทำงานของ Server Actions เหล่านี้ที่ถูกกระตุ้นโดยการส่งฟอร์ม
useFormStatus คืออะไร?
useFormStatus คือ React hook ที่คืนค่าอ็อบเจ็กต์ซึ่งมีข้อมูลเกี่ยวกับสถานะของการส่งฟอร์มล่าสุด ข้อมูลนี้รวมถึง:
- pending: ค่าบูลีนที่ระบุว่าฟอร์มกำลังถูกส่งอยู่หรือไม่
- data: อ็อบเจ็กต์
FormDataที่เกี่ยวข้องกับการส่ง - method: เมธอด HTTP ที่ใช้ในการส่ง (โดยทั่วไปคือ 'POST')
- action: ฟังก์ชัน Server Action ที่ถูกเรียกใช้งาน
ประโยชน์ของการใช้ useFormStatus
การใช้ useFormStatus มีข้อดีที่สำคัญหลายประการ:
- การจัดการสถานะที่ง่ายขึ้น: ไม่จำเป็นต้องจัดการสถานะด้วยตนเองเพื่อติดตามสถานะการส่งฟอร์ม hook จะอัปเดตโดยอัตโนมัติตามความคืบหน้าของการส่ง
- ประสบการณ์ผู้ใช้ที่ดีขึ้น: ให้การตอบสนองแบบเรียลไทม์แก่ผู้ใช้ เช่น การแสดงตัวบ่งชี้การโหลดขณะที่ฟอร์มกำลังประมวลผล หรือแสดงข้อความข้อผิดพลาดเมื่อล้มเหลว
- โค้ดที่สะอาด: ส่งเสริม codebase ที่เป็นแบบ declarative และบำรุงรักษาง่ายขึ้น โดยการแยกตรรกะการส่งฟอร์มออกจากการเรนเดอร์คอมโพเนนต์
- การผสานรวมกับ Server Actions ที่ราบรื่น: ออกแบบมาเพื่อทำงานร่วมกับ Server Actions ได้อย่างสมบูรณ์แบบ ทำให้ง่ายต่อการจัดการการส่งฟอร์มโดยตรงบนเซิร์ฟเวอร์
ตัวอย่างการใช้งาน useFormStatus ในทางปฏิบัติ
มาสำรวจตัวอย่างการใช้งานจริงหลายๆ แบบเพื่อแสดงให้เห็นถึงการใช้งาน useFormStatus ในสถานการณ์ต่างๆ
การส่งฟอร์มพื้นฐานพร้อมตัวบ่งชี้การโหลด
ตัวอย่างนี้สาธิตฟอร์มอย่างง่ายพร้อมตัวบ่งชี้การโหลดที่จะแสดงในขณะที่ฟอร์มกำลังถูกส่ง
Server Action (actions.js):
'use server'
export async function submitForm(formData) {
// Simulate a delay to demonstrate the loading state
await new Promise(resolve => setTimeout(resolve, 2000));
const name = formData.get('name');
console.log('Form submitted with name:', name);
return { message: `Form submitted successfully with name: ${name}` };
}
React Component (FormComponent.jsx):
'use client'
import { useFormStatus } from 'react-dom'
import { submitForm } from './actions'
function FormComponent() {
const { pending } = useFormStatus()
return (
)
}
export default FormComponent
ในตัวอย่างนี้ คุณสมบัติ pending จาก useFormStatus ถูกใช้เพื่อปิดการใช้งานช่องป้อนข้อมูลและปุ่มในขณะที่ฟอร์มกำลังถูกส่ง และเพื่อแสดงข้อความ "Submitting..."
การจัดการสถานะสำเร็จและข้อผิดพลาด
ตัวอย่างนี้สาธิตวิธีการจัดการสถานะสำเร็จและข้อผิดพลาดหลังจากการส่งฟอร์ม
Server Action (actions.js):
'use server'
export async function submitForm(formData) {
// Simulate a delay
await new Promise(resolve => setTimeout(resolve, 2000));
const name = formData.get('name');
if (!name) {
throw new Error('Name is required');
}
console.log('Form submitted with name:', name);
return { message: `Form submitted successfully with name: ${name}` };
}
React Component (FormComponent.jsx):
'use client'
import { useFormStatus } from 'react-dom'
import { submitForm } from './actions'
import { useState } from 'react'
function FormComponent() {
const { pending } = useFormStatus()
const [message, setMessage] = useState(null);
const [error, setError] = useState(null);
async function handleSubmit(formData) {
try {
const result = await submitForm(formData);
setMessage(result.message);
setError(null);
} catch (e) {
setError(e.message);
setMessage(null);
}
}
return (
)
}
export default FormComponent
ในตัวอย่างนี้ มีการใช้บล็อก try/catch ในฟังก์ชัน handleSubmit หาก Server Action โยนข้อผิดพลาดออกมา มันจะถูกดักจับและแสดงให้ผู้ใช้เห็น ข้อความแสดงความสำเร็จจะปรากฏขึ้นเมื่อส่งสำเร็จ
การใช้ FormData สำหรับข้อมูลที่ซับซ้อน
useFormStatus ทำงานร่วมกับ FormData ได้อย่างราบรื่น ช่วยให้คุณสามารถจัดการโครงสร้างข้อมูลที่ซับซ้อนได้อย่างง่ายดาย นี่คือตัวอย่างที่แสดงวิธีการอัปโหลดไฟล์
Server Action (actions.js):
'use server'
export async function uploadFile(formData) {
// Simulate file processing
await new Promise(resolve => setTimeout(resolve, 2000));
const file = formData.get('file');
if (!file) {
throw new Error('No file uploaded');
}
console.log('File uploaded:', file.name);
return { message: `File uploaded successfully: ${file.name}` };
}
React Component (FormComponent.jsx):
'use client'
import { useFormStatus } from 'react-dom'
import { uploadFile } from './actions'
import { useState } from 'react'
function FormComponent() {
const { pending } = useFormStatus()
const [message, setMessage] = useState(null);
const [error, setError] = useState(null);
async function handleSubmit(formData) {
try {
const result = await uploadFile(formData);
setMessage(result.message);
setError(null);
} catch (e) {
setError(e.message);
setMessage(null);
}
}
return (
)
}
export default FormComponent
ตัวอย่างนี้สาธิตวิธีการจัดการการอัปโหลดไฟล์โดยใช้ FormData server action จะดึงไฟล์จากอ็อบเจ็กต์ FormData และประมวลผล hook useFormStatus จะจัดการสถานะการโหลดในขณะที่ไฟล์กำลังถูกอัปโหลด
แนวทางปฏิบัติที่ดีที่สุดสำหรับการใช้ useFormStatus
เพื่อใช้ประโยชน์สูงสุดจาก useFormStatus ควรพิจารณาแนวทางปฏิบัติที่ดีที่สุดเหล่านี้:
- ให้การตอบสนองที่ชัดเจนแก่ผู้ใช้: ใช้สถานะ
pendingเพื่อแสดงตัวบ่งชี้การโหลดที่ให้ข้อมูลและปิดการใช้งานองค์ประกอบของฟอร์มเพื่อป้องกันการส่งซ้ำซ้อน - จัดการข้อผิดพลาดอย่างเหมาะสม: ใช้การจัดการข้อผิดพลาดเพื่อดักจับ exception ใน Server Actions ของคุณและแสดงข้อความข้อผิดพลาดที่เป็นมิตรต่อผู้ใช้
- ตรวจสอบข้อมูลบนเซิร์ฟเวอร์: ดำเนินการตรวจสอบข้อมูลฝั่งเซิร์ฟเวอร์เพื่อรับรองความสมบูรณ์และความปลอดภัยของข้อมูล
- ทำให้ Server Actions กระชับ: มุ่งเน้นให้ Server Actions ทำงานเฉพาะอย่างเพื่อปรับปรุงประสิทธิภาพและการบำรุงรักษา
- คำนึงถึงการเข้าถึงได้ (Accessibility): ตรวจสอบให้แน่ใจว่าฟอร์มของคุณสามารถเข้าถึงได้โดยการให้ป้ายกำกับที่เหมาะสม, ARIA attributes, และการรองรับการนำทางด้วยคีย์บอร์ด
กรณีการใช้งานขั้นสูง
นอกเหนือจากตัวอย่างพื้นฐานแล้ว useFormStatus ยังสามารถใช้ในสถานการณ์ที่ซับซ้อนมากขึ้นได้:
- Progressive Enhancement: ใช้ Server Actions และ
useFormStatusเพื่อปรับปรุงฟอร์มของคุณอย่างค่อยเป็นค่อยไป โดยมอบประสบการณ์พื้นฐานสำหรับผู้ใช้ที่ปิดใช้งาน JavaScript และประสบการณ์ที่สมบูรณ์ยิ่งขึ้นสำหรับผู้ที่เปิดใช้งาน JavaScript - Optimistic Updates: ใช้การอัปเดตเชิงบวกโดยการอัปเดต UI ทันทีหลังจากส่งฟอร์ม โดยสมมติว่าการส่งจะสำเร็จ และย้อนกลับการอัปเดตหากการส่งล้มเหลว
- การผสานรวมกับไลบรารีฟอร์ม: ผสาน
useFormStatusเข้ากับไลบรารีฟอร์มยอดนิยม เช่น Formik หรือ React Hook Form เพื่อจัดการสถานะและการตรวจสอบความถูกต้องของฟอร์ม แม้ว่าไลบรารีเหล่านี้มักจะมีการจัดการสถานะของตัวเอง แต่useFormStatusก็ยังมีประโยชน์สำหรับขั้นตอนการส่งข้อมูลสุดท้ายไปยัง server action
ข้อควรพิจารณาสำหรับการทำให้เป็นสากล (i18n)
เมื่อสร้างฟอร์มสำหรับผู้ชมทั่วโลก การทำให้เป็นสากล (i18n) เป็นสิ่งสำคัญ นี่คือวิธีพิจารณา i18n เมื่อใช้ useFormStatus:
- ข้อความแสดงข้อผิดพลาดที่แปลเป็นภาษาท้องถิ่น: ตรวจสอบให้แน่ใจว่าข้อความข้อผิดพลาดที่แสดงต่อผู้ใช้ได้รับการแปลเป็นภาษาที่ต้องการ ซึ่งสามารถทำได้โดยการจัดเก็บข้อความข้อผิดพลาดในไฟล์การแปลและใช้ไลบรารี เช่น
react-intlหรือi18nextเพื่อดึงคำแปลที่เหมาะสม - การจัดรูปแบบวันที่และตัวเลข: จัดการการจัดรูปแบบวันที่และตัวเลขตามสถานที่ของผู้ใช้ ใช้ไลบรารี เช่น
Intl.DateTimeFormatและIntl.NumberFormatเพื่อจัดรูปแบบค่าเหล่านี้ให้ถูกต้อง - การรองรับภาษาที่เขียนจากขวาไปซ้าย (RTL): หากแอปพลิเคชันของคุณรองรับภาษาที่เขียนจากขวาไปซ้าย (เช่น ภาษาอาหรับ, ฮิบรู) ตรวจสอบให้แน่ใจว่าฟอร์มของคุณได้รับการจัดรูปแบบอย่างเหมาะสมเพื่อรองรับเค้าโครง RTL
- การตรวจสอบความถูกต้องของฟอร์ม: ปรับแต่งกฎการตรวจสอบความถูกต้องของฟอร์มให้เข้ากับสถานที่ต่างๆ ตัวอย่างเช่น การตรวจสอบหมายเลขโทรศัพท์อาจแตกต่างกันอย่างมากในแต่ละประเทศ
ตัวอย่างข้อความแสดงข้อผิดพลาดที่แปลเป็นภาษาท้องถิ่น:
// translations/en.json
{
"form.error.nameRequired": "Please enter your name.",
"form.success.submission": "Thank you for your submission!"
}
// translations/fr.json
{
"form.error.nameRequired": "Veuillez entrer votre nom.",
"form.success.submission": "Merci pour votre soumission !"
}
// Component using react-intl
import { useIntl } from 'react-intl';
function FormComponent() {
const intl = useIntl();
const [error, setError] = useState(null);
// ...
catch (e) {
setError(intl.formatMessage({ id: 'form.error.nameRequired' }));
}
}
ข้อควรพิจารณาด้านการเข้าถึงได้ (Accessibility)
การเข้าถึงได้เป็นส่วนสำคัญของการสร้างเว็บแอปพลิเคชันที่ครอบคลุมสำหรับทุกคน นี่คือข้อควรพิจารณาด้านการเข้าถึงได้หลายประการที่ควรคำนึงถึงเมื่อใช้ useFormStatus:
- ARIA Attributes: ใช้ ARIA attributes เพื่อให้เทคโนโลยีสิ่งอำนวยความสะดวก (assistive technologies) มีข้อมูลเกี่ยวกับสถานะของฟอร์ม ตัวอย่างเช่น ใช้
aria-busy="true"บนปุ่มส่งในขณะที่ฟอร์มกำลังรอการดำเนินการ - ป้ายกำกับ (Labels): ตรวจสอบให้แน่ใจว่าฟิลด์ฟอร์มทั้งหมดมีป้ายกำกับที่ชัดเจนและสื่อความหมาย ซึ่งเชื่อมโยงกับองค์ประกอบอินพุตโดยใช้องค์ประกอบ
<label> - ข้อความแสดงข้อผิดพลาด: แสดงข้อความแสดงข้อผิดพลาดในลักษณะที่ผู้พิการสังเกตเห็นและเข้าใจได้ง่าย ใช้ ARIA attributes เช่น
aria-live="assertive"เพื่อประกาศข้อความแสดงข้อผิดพลาดให้โปรแกรมอ่านหน้าจอทราบ - การนำทางด้วยคีย์บอร์ด: ตรวจสอบให้แน่ใจว่าผู้ใช้สามารถนำทางฟอร์มได้โดยใช้คีย์บอร์ดเพียงอย่างเดียว ใช้ attribute
tabindexเพื่อควบคุมลำดับที่องค์ประกอบจะได้รับโฟกัส - ความคมชัดของสี: ตรวจสอบให้แน่ใจว่าสีข้อความและสีพื้นหลังที่ใช้ในฟอร์มมีความคมชัดเพียงพอเพื่อให้ผู้ที่มีความบกพร่องทางการมองเห็นสามารถอ่านได้ง่าย
useFormStatus เทียบกับการจัดการสถานะแบบดั้งเดิม
โดยปกติแล้ว นักพัฒนา React จะจัดการสถานะการส่งฟอร์มโดยใช้ state ของคอมโพเนนต์ (useState) หรือไลบรารีการจัดการสถานะที่ซับซ้อนกว่า (เช่น Redux, Zustand) นี่คือการเปรียบเทียบแนวทางเหล่านี้กับ useFormStatus:
| คุณสมบัติ | useFormStatus | useState | การจัดการสถานะภายนอก |
|---|---|---|---|
| ความซับซ้อน | ต่ำ | ปานกลาง | สูง |
| การผสานรวมกับ Server Actions | ราบรื่น | ต้องการการผสานรวมด้วยตนเอง | ต้องการการผสานรวมด้วยตนเอง |
| โค้ดที่ต้องเขียนซ้ำๆ (Boilerplate) | น้อยที่สุด | ปานกลาง | มาก |
| กรณีการใช้งานที่เหมาะสม | ฟอร์มที่ส่งข้อมูลไปยัง Server Actions โดยตรง | ฟอร์มอย่างง่ายที่มีสถานะจำกัด | ฟอร์มซับซ้อนที่มีสถานะร่วมกันระหว่างคอมโพเนนต์ |
useFormStatus โดดเด่นเมื่อฟอร์มของคุณโต้ตอบโดยตรงกับ React Server Actions มันช่วยลด boilerplate และทำให้กระบวนการง่ายขึ้น อย่างไรก็ตาม สำหรับฟอร์มที่ซับซ้อนมากซึ่งมีสถานะที่ใช้ร่วมกันในหลายคอมโพเนนต์ ไลบรารีการจัดการสถานะเต็มรูปแบบอาจยังคงเป็นตัวเลือกที่เหมาะสม
การแก้ไขปัญหาทั่วไป
นี่คือปัญหาทั่วไปบางประการที่คุณอาจพบเมื่อใช้ useFormStatus และวิธีแก้ไข:
useFormStatusไม่อัปเดต:- ตรวจสอบให้แน่ใจว่าคุณกำลังใช้
useFormStatusภายในองค์ประกอบ<form>ที่มี propactionตั้งค่าเป็น Server Action - ยืนยันว่า Server Action ถูกกำหนดและส่งออกอย่างถูกต้อง
- ตรวจสอบข้อผิดพลาดใดๆ ใน Server Action ที่อาจขัดขวางไม่ให้ดำเนินการเสร็จสมบูรณ์
- ตรวจสอบให้แน่ใจว่าคุณกำลังใช้
- ข้อความแสดงข้อผิดพลาดไม่แสดง:
- ตรวจสอบให้แน่ใจว่าคุณดักจับข้อผิดพลาดใน Server Action ของคุณอย่างถูกต้องและส่งคืนข้อความแสดงข้อผิดพลาด
- ยืนยันว่าคุณกำลังแสดงข้อความแสดงข้อผิดพลาดในคอมโพเนนต์ของคุณโดยใช้สถานะ
error
- ตัวบ่งชี้การโหลดไม่ปรากฏ:
- ตรวจสอบให้แน่ใจว่าคุณกำลังใช้สถานะ
pendingจากuseFormStatusเพื่อแสดงตัวบ่งชี้การโหลดตามเงื่อนไข - ตรวจสอบว่า Server Action ใช้เวลาในการดำเนินการจริงๆ (เช่น โดยการจำลองการหน่วงเวลา)
- ตรวจสอบให้แน่ใจว่าคุณกำลังใช้สถานะ
สรุป
useFormStatus เป็นวิธีที่สะอาดและมีประสิทธิภาพในการจัดการสถานะการส่งฟอร์มในแอปพลิเคชัน React ที่ใช้ Server Components ด้วยการใช้ hook นี้ คุณสามารถทำให้โค้ดของคุณง่ายขึ้น ปรับปรุงประสบการณ์ผู้ใช้ และผสานรวมกับ Server Actions ได้อย่างราบรื่น คู่มือนี้ได้ครอบคลุมพื้นฐานของ useFormStatus นำเสนอตัวอย่างที่ใช้งานได้จริง และอภิปรายแนวทางปฏิบัติที่ดีที่สุดสำหรับการใช้งานอย่างมีประสิทธิภาพ การนำ useFormStatus มาใช้ในโปรเจกต์ React ของคุณ จะช่วยให้คุณสามารถปรับปรุงการจัดการฟอร์มและสร้างแอปพลิเคชันที่แข็งแกร่งและเป็นมิตรต่อผู้ใช้สำหรับผู้ชมทั่วโลกได้