表單驗證說明
- 表單提交前,需要先進性表單驗證,驗證通過后再提交表單
- 方式一:antd-mobile 組件庫的方式(需要InputItem文本輸入組件)
- 推薦:使用更通用的 formik,React中專門用來進行表單處理和表單校驗的庫
介紹
- Github地址:formik文檔
- 場景:表單處理,表單驗證
- 優勢:輕松處理React中的復雜表單,包括:獲取表單元素的值,表單驗證和錯誤信息,處理表單提交,並且將這些內容放在一起統一處理,有利於代碼閱讀,重構,測試等
- 使用兩種方式:1. 高階組件(withFormik) 2. render-props(<Formik render={() => {}} />)
formik來實現表單校驗(★★★)
重構
- 安裝: yarn add formik
- 導入 withFormik,使用withFormit 高階組件包裹Login組件
- 為withFormit提供配置對象: mapPropsToValues / handleSubmit
- 在Login組件中,通過props獲取到values(表單元素值對象),handleSubmit,handleChange
- 使用values提供的值,設置為表單元素的value,使用handleChange設置為表單元素的onChange
- 使用handleSubmit設置為表單的onSubmit
- 在handleSubmit中,通過values獲取到表單元素值
- 在handleSubmit中,完成登錄邏輯
// Login組件中
render() {
// const { username, password } = this.state
// 通過 props 獲取高階組件傳遞進來的屬性
const { values, handleSubmit, handleChange } = this.props
return (
<div className={styles.root}>
{/* 頂部導航 */}
<NavHeader className={styles.navHeader}>賬號登錄</NavHeader>
<WhiteSpace size="xl" />
{/* 登錄表單 */}
<WingBlank>
<form onSubmit={handleSubmit}>
<div className={styles.formItem}>
<input
className={styles.input}
value={values.username}
onChange={handleChange}
name="username"
placeholder="請輸入賬號"
/>
</div>
{/* 長度為5到8位,只能出現數字、字母、下划線 */}
{/* <div className={styles.error}>賬號為必填項</div> */}
<div className={styles.formItem}>
<input
className={styles.input}
value={values.password}
onChange={handleChange}
name="password"
type="password"
placeholder="請輸入密碼"
/>
</div>
{/* 長度為5到12位,只能出現數字、字母、下划線 */}
{/* <div className={styles.error}>賬號為必填項</div> */}
<div className={styles.formSubmit}>
<button className={styles.submit} type="submit">
登 錄
</button>
</div>
</form>
<Flex className={styles.backHome}>
<Flex.Item>
<Link to="/registe">還沒有賬號,去注冊~</Link>
</Flex.Item>
</Flex>
</WingBlank>
</div>
)
}
// 使用 withFormik 高階組件包裝 Login 組件,為 Login 組件提供屬性和方法
Login = withFormik({
// 提供狀態:
mapPropsToValues: () => ({ username: '', password: '' }),
// 表單的提交事件
handleSubmit: async (values, { props }) => {
// 獲取賬號和密碼
const { username, password } = values
// 發送請求
const res = await API.post('/user/login', {
username,
password
})
console.log('登錄結果:', res)
const { status, body, description } = res.data
if (status === 200) {
// 登錄成功
localStorage.setItem('hkzf_token', body.token)
// 注意:無法在該方法中,通過 this 來獲取到路由信息
// 所以,需要通過 第二個對象參數中獲取到 props 來使用 props
props.history.go(-1)
} else {
// 登錄失敗
Toast.info(description, 2, null, false)
}
}
})(Login)
兩種表單驗證方式
-
兩種方式
- 通過validate 配置手動校驗
- 通過 validationSchema 配置項配合Yup來校驗
- 推薦: validationSchema配合Yup的方式進行表單校驗
給登錄功能添加表單驗證
- 安裝: yarn add yup (Yup 文檔),導入Yup
// 導入Yup
import * as Yup from 'yup'
- 在 withFormik 中添加配置項 validationSchema,使用 Yup 添加表單校驗規則
- 在 Login 組件中,通過 props 獲取到 errors(錯誤信息)和 touched(是否訪問過,注意:需要給表單元素添加 handleBlur 處理失焦點事件才生效!)
- 在表單元素中通過這兩個對象展示表單校驗錯誤信
示例代碼:
// 使用 withFormik 高階組件包裝 Login 組件,為 Login 組件提供屬性和方法
Login = withFormik({
...
// 添加表單校驗規則
validationSchema: Yup.object().shape({
username: Yup.string()
.required('賬號為必填項')
.matches(REG_UNAME, '長度為5到8位,只能出現數字、字母、下划線'),
password: Yup.string()
.required('密碼為必填項')
.matches(REG_PWD, '長度為5到12位,只能出現數字、字母、下划線')
}),
...
})(Login)
在結構中需要渲染錯誤信息:
{/* 登錄表單 */}
<WingBlank>
<form onSubmit={handleSubmit}>
... 用戶名的錯誤提示
{errors.username && touched.username && (
<div className={styles.error}>{errors.username}</div>
)}
... 密碼框的錯誤提示
{errors.password && touched.password && (
<div className={styles.error}>{errors.password}</div>
)}
...
</WingBlank>
簡單處理
- 導入 Form組件,替換form元素,去掉onSubmit
- 導入Field組件,替換input表單元素,去掉onChange,onBlur,value
- 導入 ErrorMessage 組件,替換原來的錯誤消息邏輯代碼
- 去掉所有 props
示例代碼:
// 導入withFormik
import { withFormik, Form, Field, ErrorMessage } from 'formik'
<Form>
{/* 賬號 */}
<div className={styles.formItem}>
<Field
className={styles.input}
name="username"
placeholder="請輸入賬號"
/>
</div>
<ErrorMessage
className={styles.error}
name="username"
component="div"
/>
{/* 密碼 */}
<div className={styles.formItem}>
<Field
className={styles.input}
name="password"
type="password"
placeholder="請輸入密碼"
/>
</div>
<ErrorMessage
className={styles.error}
name="password"
component="div"
/>
<div className={styles.formSubmit}>
<button className={styles.submit} type="submit">
登 錄
</button>
</div>
</Form>