在 Day 21 | React入門:React 中的表單 ( Form )
的文章當中有提到:
表單是網站中,收集使用者資料的主要方式,例如我們常登入社群所需要的帳號密碼,甚至是貼文底下的留言,都是一種表單。
然而,如果某些必填或是格式錯誤的資料被送出之後,例如:
這些資料不應該直接傳送到後端,否則會造成不必要的檢查與資源浪費。我們應該先在前端阻止表單送出,並清楚標示出錯誤的欄位與提示訊息,這時候就需要表單驗證的方法。
表單驗證的使用方式有很多,這裡我主要提供我在網路教學看到的一種方法:
const [email, setEmail] = useState("");
const [message, setMessage] = useState("");
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(false);
const handleSubmit = (e) => {
e.preventDefault();
const errors = validate({ email, message });
setFormErrors(errors);
setIsSubmit(true);
};
e.preventDefault()
:阻止表單的預設行為(避免頁面重新整理)const errors = validate({ email, message })
:呼叫驗證函式 ( validate ),將目前表單的輸入值帶入檢查,如果有欄位不符合規則,函式就會回傳一個錯誤訊息的物件setFormErrors(errors)
:將 validate 回傳的錯誤訊息存入 formErrors
這個 state,讓畫面上顯示相對的錯誤提示setIsSubmit(true);
:設定表單嘗試送出,用於後續判斷是否顯示送出成功或錯誤訊息
useEffect(() => {
if (Object.keys(formErrors).length === 0 && isSubmit) {
alert("送出成功");
}
}, [formErrors, isSubmit]);
Object.keys(formErrors).length === 0 && isSubmit
:判斷錯誤訊息物件是否為空,並確認表單已經嘗試送出。若兩者都成立,代表表單驗證通過,可以進行送出動作[formErrors, isSubmit]
:依賴陣列,只要其中一個的值有變化,useEffect
就會再次執行
const validate = (values) => {
const errors = {};
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i;
if (!values.email) {
errors.email = "請輸入電子郵件";
} else if (!regex.test(values.email)) {
errors.email = "電子郵件格式不正確";
}
if (!values.message) {
errors.message = "請輸入內容";
} else if (values.message.length < 5) {
errors.message = "內容至少需要 5 個字";
}
return errors;
};
const errors = {}
:先建立一個空物件,用來暫存各個欄位可能的錯誤訊息const regex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i
:定義一個用來驗證 Email 格式的正則表達式,用來判斷使用者輸入的值是否為有效的電子郵件
Contact.js
import { useState, useEffect } from "react";
export default function Contact() {
const [email, setEmail] = useState("");
const [message, setMessage] = useState("");
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(false);
const handleSubmit = (e) => {
e.preventDefault();
const errors = validate({ email, message });
setFormErrors(errors);
setIsSubmit(true);
};
useEffect(() => {
if (Object.keys(formErrors).length === 0 && isSubmit) {
alert("送出成功");
}
}, [formErrors, isSubmit]);
const validate = (values) => {
const errors = {};
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i;
if (!values.email) {
errors.email = "請輸入電子郵件";
} else if (!regex.test(values.email)) {
errors.email = "電子郵件格式不正確";
}
if (!values.message) {
errors.message = "請輸入內容";
} else if (values.message.length < 5) {
errors.message = "內容至少需要 5 個字";
}
return errors;
};
return (
<div className="contact">
<h3>聯絡我們</h3>
{Object.keys(formErrors).length === 0 && isSubmit ? (
<div className="ui message success">送出成功</div>
) : null}
<form onSubmit={handleSubmit}>
<label>
<span>電子郵件:</span>
<input
type="text"
name="email"
value={email}
placeholder="請輸入電子郵件"
onChange={(e) => setEmail(e.target.value)}
/>
</label>
<p style={{ color: "red" }}>{formErrors.email}</p>
<label>
<span>內容:</span>
<textarea
name="message"
value={message}
placeholder="請輸入內容"
onChange={(e) => setMessage(e.target.value)}
></textarea>
</label>
<p style={{ color: "red" }}>{formErrors.message}</p>
<button>送出</button>
</form>
</div>
);
}
瀏覽器執行畫面:錯誤訊息
瀏覽器執行畫面:送出成功
onChange
):例如輸入 Email 時,一旦格式錯誤,就立刻在欄位下方顯示紅字提醒,而不是等到點擊送出才檢查