本篇文章主要介紹react+hooks實(shí)現(xiàn)表單提交的基礎(chǔ)案例,其中依賴(lài)于ant-design4.0版本的UI組件。其中分為兩種表單提交場(chǎng)景
首先講解下使用Form表單的一些注意點(diǎn):
如何獲取表單實(shí)例?
使用Form組件中自帶的hooks可以獲取到表單實(shí)例 const [form] = Form.useForm()
將form組件掛在到Form組件上 <Form form={form}></Form>
此時(shí)form變量就是Form表單的實(shí)例,可以調(diào)用實(shí)例上的方法直接操作表單
表單字段如何自定義校驗(yàn)規(guī)則?
在Form.Item組件中的rules屬性中可以添加validator屬性,該屬性值為一個(gè)函數(shù),可接收三個(gè)參數(shù):rule ,
value, callback。驗(yàn)證不通過(guò)在callback中傳入錯(cuò)誤原因即可,驗(yàn)證通過(guò)直接調(diào)用callback就行
防止表單重復(fù)提交 ?
提交時(shí)調(diào)用提交接口的那個(gè)函數(shù)一定要用useCallback hooks, useCallback返回一個(gè)函數(shù),此場(chǎng)景中主要是為了實(shí)時(shí)監(jiān)聽(tīng)flag(提交請(qǐng)求是否完成)值的變化來(lái)判斷是否可以發(fā)起請(qǐng)求
表單提交示例代碼
-
表單內(nèi)提交:即提交按鈕在form組件內(nèi), 注意點(diǎn):
提交按鈕必須在Form表單內(nèi),且Button組件要添加htmlType="submit",這樣點(diǎn)擊按鈕才會(huì)自動(dòng)提交表單
import React, { useState, useCallback} from 'react'
import { Form, Input, Radio, Select, Button,message} from 'antd'
import {register} from '../../api/formCase'
import styles from './index.module.scss'
const {Option} = Select
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 10 },
}
let FormCase:any = ()=> {
const [flag, setFlag] = useState<boolean>(false)
const [form] = Form.useForm()
const validatePass = (rule:any, value:any, callback:any)=> {
const reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/
if (value) {
if(reg.test(value)) {
callback()
} else {
callback('至少1個(gè)大寫(xiě)字母,1個(gè)小寫(xiě)字母和1個(gè)數(shù)字')
}
} else {
callback('請(qǐng)輸入密碼')
}
}
const validatePhone = (rule:any, value:any, callback:any)=> {
const reg = /^[1][3,4,5,7,8,9][0-9]{9}$/
console.log(rule, value)
if (value) {
if(reg.test(value)) {
callback()
} else {
callback('手機(jī)號(hào)格式不正確')
}
} else {
callback('請(qǐng)輸入手機(jī)號(hào)')
}
}
const onFinish = useCallback((values) => {
if(flag) return
setFlag(true)
register(values).then(()=> {
message.success('注冊(cè)成功');
}).finally(() => {
setFlag(false)
})
},[flag])
const onReset = () => {
form.resetFields()
}
return (
<Form {...formItemLayout} onFinish={onFinish} initialValues={{sex: 1}} form={form}>
<Form.Item name="name" label="用戶(hù)名:" rules={[{required:true, message:'請(qǐng)輸入用戶(hù)名'}]}>
<Input maxLength={10} />
</Form.Item>
<Form.Item name="password" label="密碼:"rules={[{required:true, validator:validatePass}]}>
<Input minLength={8} maxLength={20} />
</Form.Item>
<Form.Item name="phone" label="手機(jī)號(hào):" rules={[{required: true, validator: validatePhone}]}>
<Input />
</Form.Item>
<Form.Item name="sex" label="性別:">
<Radio.Group>
<Radio value={1}>男</Radio>
<Radio value={0}>女</Radio>
</Radio.Group>
</Form.Item>
<Form.Item name="country" label="性別:">
<Select placeholder="請(qǐng)選擇國(guó)家">
<Option value="china">中國(guó)</Option>
<Option value="usa">美國(guó)</Option>
</Select>
</Form.Item>
{
<Form.Item wrapperCol={{ span: 10, offset: 6 }}>
<div className={styles.btn_wrap}>
<Button className={styles.btn} type="primary" htmlType="submit">
form內(nèi)提交表單
</Button>
<Button className={styles.btn} onClick={onReset}>
重置
</Button>
</div>
</Form.Item>
}
</Form>
)
}
export default FormCase
-
表單外提交:即表單提交按鈕與表單不在同一個(gè)組件中(此處按鈕在父組件,表單為子組件為例)
注意點(diǎn): 此種場(chǎng)景需要父組件具有調(diào)用子組件方法的能力,需要使用useImperativeHandle, forwardRef 這兩個(gè)hooks將子組件的方法暴露給父組件
import React, { useState, useRef, useImperativeHandle,forwardRef, useCallback} from 'react'
import { Form, Input, Radio, Select, Button,Divider,message, Col } from 'antd'
import {register} from '../../api/formCase'
import styles from './index.module.scss'
const {Option} = Select
const formItemLayout = {
labelCol: { span: 6 },
wrapperCol: { span: 10 },
}
let FormContent:any = (props:any, ref:any)=> {
const [flag, setFlag] = useState<boolean>(false)
const [form] = Form.useForm()
const validatePass = (rule:any, value:any, callback:any)=> {
const reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/
if (value) {
if(reg.test(value)) {
callback()
} else {
callback('至少1個(gè)大寫(xiě)字母,1個(gè)小寫(xiě)字母和1個(gè)數(shù)字')
}
} else {
callback('請(qǐng)輸入密碼')
}
}
const validatePhone = (rule:any, value:any, callback:any)=> {
const reg = /^[1][3,4,5,7,8,9][0-9]{9}$/
console.log(rule, value)
if (value) {
if(reg.test(value)) {
callback()
} else {
callback('手機(jī)號(hào)格式不正確')
}
} else {
callback('請(qǐng)輸入手機(jī)號(hào)')
}
}
const onFinish = useCallback((values) => {
if(flag) return
setFlag(true)
register(values).then(()=> {
message.success('注冊(cè)成功');
}).finally(() => {
setFlag(false)
})
},[flag])
useImperativeHandle(ref, () => ({
submitForm: () => {
form.submit()
},
resetForm: () => {
form.resetFields()
}
}));
return (
<Form {...formItemLayout} onFinish={onFinish} initialValues={{sex: 1}} form={form}>
<Form.Item name="name" label="用戶(hù)名:" rules={[{required:true, message:'請(qǐng)輸入用戶(hù)名'}]}>
<Input maxLength={10} />
</Form.Item>
<Form.Item name="password" label="密碼:"rules={[{required:true, validator:validatePass}]}>
<Input minLength={8} maxLength={20} />
</Form.Item>
<Form.Item name="phone" label="手機(jī)號(hào):" rules={[{required: true, validator: validatePhone}]}>
<Input />
</Form.Item>
<Form.Item name="sex" label="性別:">
<Radio.Group>
<Radio value={1}>男</Radio>
<Radio value={0}>女</Radio>
</Radio.Group>
</Form.Item>
<Form.Item name="country" label="性別:">
<Select placeholder="請(qǐng)選擇國(guó)家">
<Option value="china">中國(guó)</Option>
<Option value="usa">美國(guó)</Option>
</Select>
</Form.Item>
</Form>
)
}
FormContent = forwardRef(FormContent)
function FormCase() {
const formRef:any = useRef()
const formSubmit = () => {
formRef.current.submitForm()
}
const formReset = () => {
formRef.current.resetForm()
}
return(
<div>
<FormContent ref={formRef} />
<Divider />
<Col span={24} offset={6}>
<div className={styles.btn_wrap}>
<Button className={styles.btn} type="primary" onClick={formSubmit}>form外提交表單</Button>
<Button className={styles.btn} onClick={formReset}>重置</Button>
</div>
</Col>
</div>
)
}
export default FormCase