02- react+hooks實(shí)現(xiàn)form表單提交

本篇文章主要介紹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

案例代碼:https://github.com/lee-won/reactCaseDome

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容