在現代 Web 應用開發中,表單的管理與驗證往往是開發過程中的一大挑戰。上一篇文章中,我們探討了如何追蹤使用者行為並優化應用體驗,而今天,我們的焦點是表單管理。具體來說,我們將深入學習如何使用 react-hook-form 來高效處理 "Let’s Collaborate" 表單,並深入探討它背後的原理與最佳實踐。

react-hook-form在大型應用程式中,表單管理往往是一項重複且容易出錯的工作。React 的受控組件(controlled components)在處理複雜表單時,經常會導致性能問題,例如頻繁重渲染或狀態管理困難。這時,react-hook-form 提供了以下的優勢:
react-hook-form 提供的 API 如 useForm() 和 register(),讓開發者可以快速管理表單並實現自定義邏輯。
接下來,我們將以 "Let’s Collaborate" 表單為例,展示如何將 react-hook-form 集成到項目中,並結合表單驗證及性能優化進行實作。
react-hook-form首先,我們需要安裝 React-Hook-Form:
npm install react-hook-form
安裝 react-hook-form 是實現高效表單管理的第一步,它提供了基本的表單處理功能,後續的驗證和數據處理邏輯都將基於這個庫。
以下是基於 react-hook-form 實現的表單組件代碼,我們將探討其內部機制及設計選擇:
import React from 'react';
import { useForm } from 'react-hook-form';
import * as styles from '@/components/Form/ContactForm.module.scss';
const ContactForm = () => {
    // 使用 useForm hook 來管理表單
    const { register, handleSubmit, formState: { errors } } = useForm();
    // 表單提交處理
    const onSubmit = (data) => {
        console.log('Form submitted:', data);
        // 這裡可以加入 API 提交邏輯
    };
    return (
        <form className={styles.contactForm} onSubmit={handleSubmit(onSubmit)}>
            <div className={styles.formGroup}>
                <label htmlFor="name">Name</label>
                <input
                    type="text"
                    {...register('name', { required: 'Name is required' })}
                    placeholder="Your Name"
                />
                {errors.name && <p className={styles.errorText}>{errors.name.message}</p>}
            </div>
            <div className={styles.formGroup}>
                <label htmlFor="email">Email</label>
                <input
                    type="email"
                    {...register('email', {
                        required: 'Email is required',
                        pattern: {
                            value: /\S+@\S+\.\S+/,
                            message: 'Enter a valid email',
                        },
                    })}
                    placeholder="Your Email"
                />
                {errors.email && <p className={styles.errorText}>{errors.email.message}</p>}
            </div>
            <div className={styles.formGroup}>
                <label htmlFor="serviceItem">Service Items</label>
                <select
                    {...register('serviceItem', { required: 'Please select a service item' })}
                >
                    <option value="">Select a service</option>
                    <option value="design">Design</option>
                    <option value="development">Development</option>
                    <option value="consultation">Consultation</option>
                </select>
                {errors.serviceItem && <p className={styles.errorText}>{errors.serviceItem.message}</p>}
            </div>
            <div className={styles.formGroup}>
                <label htmlFor="projectDetails">Project Details</label>
                <textarea
                    {...register('projectDetails', { required: 'Project details are required' })}
                    placeholder="Describe your project"
                ></textarea>
                {errors.projectDetails && <p className={styles.errorText}>{errors.projectDetails.message}</p>}
            </div>
            <button type="submit" className={styles.submitButton}>
                Submit
                <img src={require(`@/assets/icons/Submit.svg`)} alt="Submit" className={styles.submitIcon} />
            </button>
        </form>
    );
};
export default ContactForm;
說明:
useForm:useForm() 是 react-hook-form 的核心 Hook。它提供了對表單數據的全面控制,並簡化了表單輸入、驗證及提交邏輯。這裡我們從 useForm 中提取了 register、handleSubmit 和 errors,這三個函數和對象是管理表單邏輯的關鍵。register 用於註冊輸入框:我們通過 register 函數將表單元素(如 input 和 textarea)與表單管理系統連接。這樣 react-hook-form 就可以跟蹤這些元素的狀態並進行驗證。required、pattern 等。這樣當用戶提交表單時,react-hook-form 會自動檢查這些條件是否滿足,如果不滿足,則在 errors 對象中記錄相應的錯誤資訊。react-hook-form 是基於非受控組件的,React 的狀態不會在每次輸入變動時被更新。相比於使用 useState 管理表單輸入,這種方式顯著減少了重渲染次數,提高了應用的響應速度。這部分展示了如何在網頁上整合聯絡資訊(如營業時間、聯絡方式)與嵌入的表單,並使用 i18n 進行多語言處理。這樣可以實現根據使用者語言動態顯示不同語言的內容,提升國際化的支持。
import React from 'react';
import { useTranslation } from 'react-i18next';
import * as styles from './ContactSection.module.scss';
import ContactForm from '@/components/Form/ContactForm';
const ContactSection = ({ id }) => {
    const { t } = useTranslation();  // 引入翻譯函數
    return (
        <div id={id} className={styles.subcontainer}>
            <div className={styles.infoSection}>
                <h2 className={styles.title}>{t('collaborate.title')}</h2>
                <p className={styles.description}>
                    {t('collaborate.description')}
                </p>
                <div className={styles.infoBox}>
                    <div className={styles.infoItem}>
                        <img src={require(`@/assets/icons/Open.svg`)} alt="Open" className={styles.icon} />
                        <div>
                            <div className={styles.infoTitle}>{t('collaborate.businessHours')}</div>
                            <div className={styles.description}>{t('collaborate.hours')}</div>
                        </div>
                    </div>
                    <div className={styles.infoItem}>
                        <img src={require(`@/assets/icons/Newsletter.svg`)} alt="Email" className={styles.icon} />
                        <div>
                            <div className={styles.infoTitle}>{t('collaborate.email')}</div>
                            <div className={styles.description}>carol.cheng@luma-c.com</div>
                        </div>
                    </div>
                    <div className={styles.infoItem}>
                        <img src={require(`@/assets/icons/LINE.svg`)} alt="Chat" className={styles.icon} />
                        <div>
                            <div className={styles.infoTitle}>{t('collaborate.lineId')}</div>
                            <div className={styles.description}>@430trfzv</div>
                        </div>
                    </div>
                </div>
            </div>
            <ContactForm /> {/* 嵌入表單組件 */}
        </div>
    );
}
export default ContactSection;
這裡,我們展示了聯絡資訊(如營業時間、聯絡信箱和 LINE ID),並以多語言格式呈現,用戶根據不同語言環境能看到本地化的聯絡資訊描述。
現在表單具備了基本的驗證功能,你可以進行以下幾項測試來確保表單正常運作:
abc@)時,表單應該提示 Email 格式錯誤。react-hook-form 不僅為我們提供了一個輕量級、高效能的表單管理方案,還通過簡潔的 API 幫助我們輕鬆應對複雜表單的驗證與狀態管理。從基本的輸入驗證到異步驗證,甚至是多步驟表單,react-hook-form 皆能靈活應對。
如果你正在尋找一個能顯著提升表單效能的工具,不妨試試 react-hook-form。在下一篇文章中,我們將進一步探討如何將表單數據提交到後端 API,並處理表單提交的狀態與回應。
✨ 流光館Luma<∕> ✨ 期待與你繼續探索更多技術知識!