溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

使用Formik輕松開(kāi)發(fā)更高質(zhì)量的React表單(三)<Formik />解析

發(fā)布時(shí)間:2020-07-17 16:28:34 來(lái)源:網(wǎng)絡(luò) 閱讀:5460 作者:googlingman 欄目:web開(kāi)發(fā)

提醒和建議



根據(jù)我的粗淺經(jīng)驗(yàn),如果您對(duì)Formik感興趣,并且想深入學(xué)習(xí)與使用這個(gè)庫(kù),我建議您還是先對(duì)redux-form的使用邏輯與有關(guān)概念有所了解,而且理解和使用方面也變得容易得多的多。因?yàn)镕ormik中許多概念與形式與redux-form極其類似,但是各方面都簡(jiǎn)化了很多,因?yàn)樗辉僖蕾囉诩s束整個(gè)前面存儲(chǔ)的Redux store的限制,由于整個(gè)前端使用一個(gè)store存儲(chǔ),所以,隨著表單數(shù)量與形式變得越來(lái)越復(fù)雜,系統(tǒng)的屬性可能會(huì)受到嚴(yán)重影響——這是Formik產(chǎn)生的主要原因,F(xiàn)ormik干脆不使用Redux,而直接操作React組件,這就有可能使得編寫表單元素雖然簡(jiǎn)單(HTML5)但比較冗長(zhǎng),于是Formik也引入了類似于redux-form的一些API與props等概念(但絕對(duì)有區(qū)別)。
另外請(qǐng)注意,為了與其他流行的React文章保持一致,有些單詞沒(méi)有必要翻譯過(guò)來(lái),例如store, values,props,shape,errors,等等。另外,touchtouched這個(gè)詞在Formik中廣泛使用,意思是表單中某個(gè)字段被點(diǎn)擊過(guò),此時(shí)用戶可能沒(méi)有輸入什么數(shù)據(jù),也有可能輸入了新的數(shù)據(jù),都稱為touched。因此,后面的譯文中一般翻譯為「動(dòng)過(guò)」,個(gè)別地方翻譯成「潤(rùn)色」,請(qǐng)理解其使用情形就是。

關(guān)于<Formik />組件



<Formik>是一個(gè)幫助構(gòu)建表單的組件,它也使用了類似于當(dāng)前一些流行的庫(kù)(如React Motion和 React Router)的render這種prop模式。請(qǐng)參考下面的代碼:

import React from 'react';
import { Formik } from 'formik';

const BasicExample = () => (
  <div>
    <h2>My Form</h2>
    <Formik
      initialValues={{ name: 'jared' }}
      onSubmit={(values, actions) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          actions.setSubmitting(false);
        }, 1000);
      }}
      render={props => (
        <form onSubmit={props.handleSubmit}>
          <input
            type="text"
            onChange={props.handleChange}
            onBlur={props.handleBlur}
            value={props.values.name}
            name="name"
          />
          {props.errors.name && <div id="feedback">{props.errors.name}</div>}
          <button type="submit">Submit</button>
        </form>
      )}
    />
  </div>
);

Formik渲染方法



<Formik />這個(gè)API共提供了三種渲染方法,它們是:

  • <Formik component>

  • <Formik render>

  • <Formik children>

Formik props列表分析



上面所有三種渲染方法都會(huì)傳遞相同的props。接下來(lái),我們對(duì)props每一個(gè)分量作相應(yīng)的解釋。

(1)dirty: boolean

當(dāng)values與初始值不絕對(duì)相等時(shí)這個(gè)屬性的值會(huì)返回true;否則返回false(Returns true if values are not deeply equal from initial values, false otherwise)。注意:dirty屬性是只讀的,不應(yīng)該直接修改它。

(2)errors: { [field: string]: string }

其中包含F(xiàn)orm校驗(yàn)錯(cuò)誤信息。這些信息應(yīng)當(dāng)與表單的定義于initialValues中的值(values)保持一致。如果你在使用validationSchema(也推薦你使用),那么數(shù)據(jù)(原文使用的是“keys and shape”,關(guān)于shape一詞在React文章中經(jīng)常見(jiàn)到,這里不便直譯)應(yīng)當(dāng)與你的模式定義準(zhǔn)確匹配。 從內(nèi)部實(shí)現(xiàn)代碼來(lái)看,F(xiàn)ormik會(huì)根據(jù)你提供的數(shù)據(jù)轉(zhuǎn)換原始的Yup校驗(yàn)錯(cuò)誤信息。如果你在使用validate屬性,那么此函數(shù)會(huì)確定錯(cuò)誤對(duì)象的具體信息。

handleBlur: (e: any) => void

這是onBlur對(duì)應(yīng)的事件處理器函數(shù)。當(dāng)你需要跟蹤某個(gè)輸入字段是否被“動(dòng)過(guò)”(touched)時(shí)很有用。用法比如:<input onBlur={handleBlur} ... />

【注意】本屬性僅適用于DOM開(kāi)發(fā);如果是React Native開(kāi)發(fā)則需使用setFieldTouched代替。

handleChange: (e: React.ChangeEvent<any>) => void

這是一個(gè)典型的輸入字段內(nèi)容變化時(shí)要觸發(fā)的事件處理器。當(dāng)key為事件發(fā)出的輸入字段的name屬性時(shí)這一調(diào)用會(huì)更新values。如果name不存在,那么handleChange函數(shù)會(huì)進(jìn)一步查找輸入字段(input)的id屬性。請(qǐng)注意: 這里的input意指所有HTML input標(biāo)簽。

【注意】本屬性僅適用于DOM開(kāi)發(fā);如果是React Native開(kāi)發(fā)則需使用setFieldValue代替。

handleReset: () => void

這是表單復(fù)位處理器函數(shù),調(diào)用它將把表單還原到初始值狀態(tài)。用法比如:<button onClick={handleReset}>...</button>

handleSubmit: (e: React.FormEvent<HTMLFormEvent>) => void

這是表單提交處理器函數(shù)。 用法比如:<form onSubmit={props.handleSubmit}>...</form>。請(qǐng)結(jié)合本系列文章第一篇中「表單提交原理」部分加以理解。

isSubmitting: boolean

這個(gè)屬性值代表了表單提交的當(dāng)前狀態(tài)。如果表單在提交中將返回true;否則返回false。重要提醒:一旦你嘗試提交表單,F(xiàn)ormik就會(huì)把這個(gè)值設(shè)置為true。請(qǐng)結(jié)合本系列文章第一篇中「表單提交原理」部分加以理解。

isValid: boolean

在不發(fā)生錯(cuò)誤的情況下這個(gè)屬性值將為true;或者返回當(dāng)表單處于pristine條件(例如沒(méi)有dirty)時(shí)會(huì)返回isInitialValid的結(jié)果值。

isValidating: boolean

如果Formik正在運(yùn)行任何檢驗(yàn)函數(shù),則此屬性返回true;否則,返回false。想更多地了解在表單提交過(guò)程中isValidating屬性發(fā)生了什么變化,請(qǐng)結(jié)合閱讀本系列文章第一篇中「表單提交原理」部分。

resetForm: (nextValues?: Values) => void

強(qiáng)行復(fù)位表單。這個(gè)調(diào)用會(huì)清除所有錯(cuò)誤及字段「潤(rùn)色」信息,并且設(shè)置isSubmitting為false,設(shè)置isValidating為false,并且把mapPropsToValues返回值設(shè)置為當(dāng)前的WrappedComponent的props或者是傳遞過(guò)去的參數(shù)。注意:當(dāng)在componentWillReceiveProps內(nèi)部調(diào)用resetForm時(shí),這是很有用的。

setErrors: (fields: { [field: string]: string }) => void

強(qiáng)行設(shè)置errors信息。

setFieldError: (field: string, errorMsg: string) => void

強(qiáng)行設(shè)置給定字段的error信息。注意,這里的參數(shù)field應(yīng)當(dāng)匹配你希望更新的errors中的key。這個(gè)屬性在編寫定制的輸入錯(cuò)誤信息處理器函數(shù)時(shí)非常有用。

setFieldTouched: (field: string, isTouched: boolean, shouldValidate?: boolean) => void

強(qiáng)行設(shè)置給定字段的touched狀態(tài)值。注意,這里的參數(shù)field應(yīng)當(dāng)匹配你想更新的「動(dòng)過(guò)」的key。這個(gè)屬性在編寫定制的blur處理器函數(shù)時(shí)非常有用。如果validateOnBlur的值設(shè)置為true(默認(rèn)即為此值),那么調(diào)用這個(gè)方法會(huì)觸發(fā)校驗(yàn)運(yùn)行。你也可以通過(guò)傳遞第三個(gè)參數(shù)為false來(lái)顯式地禁止或者跳過(guò)校驗(yàn)。

submitForm: () => void

觸發(fā)表單提交操作。

submitCount: number

代表用戶嘗試提交表單的次數(shù)。當(dāng)調(diào)用handleSubmit時(shí)此屬性的值會(huì)加1;但是調(diào)用handleReset后該屬性值會(huì)復(fù)位。請(qǐng)注意, submitCount是一個(gè)只讀屬性,不能直接修改。

setFieldValue: (field: string, value: any, shouldValidate?: boolean) => void

強(qiáng)制設(shè)置一個(gè)字段的值。其中,參數(shù)field應(yīng)當(dāng)匹配你希望更新的values中的key。 該屬性在編寫定制的change事件處理函數(shù)時(shí)很有用。當(dāng)validateOnChange為true (默認(rèn)即是這個(gè)值)時(shí),調(diào)用此屬性對(duì)應(yīng)的函數(shù)會(huì)觸發(fā)校驗(yàn)的執(zhí)行。當(dāng)然,你還可以通過(guò)傳遞第三個(gè)參數(shù)為false來(lái)顯式地禁止或者跳過(guò)校驗(yàn)。

setStatus: (status?: any) => void

強(qiáng)制設(shè)置一個(gè)頂級(jí)的狀態(tài)值。這個(gè)調(diào)用用于控制你的表單的任意頂級(jí)狀態(tài)。例如,你可以使用它來(lái)把API響應(yīng)傳遞回在handleSubmit調(diào)用中的你的組件內(nèi)部。

setSubmitting: (isSubmitting: boolean) => void

強(qiáng)制設(shè)置isSubmitting屬性的值。

setTouched: (fields: { [field: string]: boolean }) => void

強(qiáng)制設(shè)置touched屬性的值。

setValues: (fields: { [field: string]: any }) => void

強(qiáng)制設(shè)置values對(duì)象的值。

status?: any

這是一個(gè)頂級(jí)的狀態(tài)對(duì)象,你可以使用它來(lái)描述使用其他方法無(wú)法表達(dá)/存儲(chǔ)的表單狀態(tài)。在捕獲或者傳遞API響應(yīng)給你的內(nèi)部組件時(shí)這個(gè)屬性很有用。
【注意】你僅能通過(guò)調(diào)用setStatus: (status?: any) => void來(lái)修改status。

touched: { [field: string]: boolean }

此屬性用于潤(rùn)色表單中對(duì)應(yīng)的字段值。每一個(gè)鍵都相應(yīng)于一個(gè)剛剛被「動(dòng)過(guò)」(touched)或者訪問(wèn)過(guò)的字段。

values: { [field: string]: any }

這是你的表單中的values對(duì)象。其中存儲(chǔ)了mapPropsToValues (如果指定的話)對(duì)應(yīng)的結(jié)果數(shù)據(jù),或者存儲(chǔ)那些傳遞給你的被包裝組件(wrapped component)的不是函數(shù)形式的props。
【說(shuō)明】包裝組件(wrapped component)一詞在諸多React/Redux文章中多見(jiàn),即是指使用類似于redux-form的reduxForm API封裝后的新組件。

validateForm: (values?: any) => void

根據(jù)指定的方式強(qiáng)制你的validate屬性對(duì)應(yīng)的校驗(yàn)函數(shù)或者是調(diào)用validateSchema。注意,你可以選擇性地傳遞數(shù)值進(jìn)行校驗(yàn),當(dāng)然這將相應(yīng)地修改Formik狀態(tài);否則,它會(huì)使用表單的當(dāng)前values。

validateField: (field: string) => void

強(qiáng)制調(diào)用表單的validate屬性對(duì)應(yīng)的函數(shù)——如果指定了相應(yīng)字段的話。Formik將使用當(dāng)前字段值。

component

下面給出此屬性的典型使用方法:

<Formik component={ContactForm} />;

const ContactForm = ({
  handleSubmit,
  handleChange,
  handleBlur,
  values,
  errors,
}) => (
  <form onSubmit={handleSubmit}>
    <input
      type="text"
      onChange={handleChange}
      onBlur={handleBlur}
      value={values.name}
      name="name"
    />
    {errors.name && <div>{errors.name}</div>}
    <button type="submit">Submit</button>
  </form>
};

【注意】<Formik component> 的優(yōu)先級(jí)會(huì)高于<Formik render>;因此,你不要在同一個(gè)<Formik>中同時(shí)使用二者。

render: (props: FormikProps<Values>) => ReactNode

這個(gè)屬性相當(dāng)重要,請(qǐng)參考如下代碼了解其用法:

<Formik render={props => <ContactForm {...props} />} />

<Formik
  render={({ handleSubmit, handleChange, handleBlur, values, errors }) => (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        onChange={handleChange}
        onBlur={handleBlur}
        value={values.name}
        name="name"
      />
      {errors.name &&
        <div>
          {errors.name}
        </div>}
      <button type="submit">Submit</button>
    </form>
  )}
/>

children: func

使用方法見(jiàn)下面的代碼片斷:

&lt;Formik children={props =&gt; &lt;ContactForm {...props} /&gt;} /&gt;

//或者使用下面的方式...

<Formik>
  {({ handleSubmit, handleChange, handleBlur, values, errors }) => (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        onChange={handleChange}
        onBlur={handleBlur}
        value={values.name}
        name="name"
      />
      {errors.name &&
        <div>
          {errors.name}
        </div>}
      <button type="submit">Submit</button>
    </form>
  )}
</Formik>

enableReinitialize?: boolean

默認(rèn)值為false。此屬性用于在initialValues變化時(shí)控制是否重置表單。

isInitialValid?: boolean

默認(rèn)值為false。用于控制表單加載前的isValid屬性的初始值。你也可以傳遞一個(gè)函數(shù)。此屬性用于當(dāng)你想在表單初始加載時(shí)啟用/禁用一次提交/復(fù)位按鈕操作時(shí)。

initialValues?: Values

相應(yīng)于表單初始字段值。Formik將使用這些值來(lái)生成例如props.values這樣的方法組件。

即使你的表單默認(rèn)情況下為空,你也必須使用初始值來(lái)初始化所有字段;否則,React會(huì)拋出異步,說(shuō)你已經(jīng)把一個(gè)輸入字段從未控制(uncontrolled)狀態(tài)改變成了可控制(controlled)狀態(tài)。
【注意】 initialValues并不適用于高階組件(higher-order component);在高階組件情況下,你需要使用mapPropsToValues代之。

onReset?: (values: Values, formikBag: FormikBag) => void

對(duì)應(yīng)于你可選擇使用的表單復(fù)位處理器函數(shù)。其中的參數(shù)是你的表單values,還有一個(gè)"FormikBag"值。

onSubmit: (values: Values, formikBag: FormikBag) => void

這是表單提交處理器函數(shù)。其中的參數(shù)是你的表單values,還有一個(gè)"FormikBag"值——其中提供了一個(gè)包含被注入的屬性(props)和方法(例如所有以set開(kāi)頭——如set<Thing>的方法,還有方法resetForm)的子集的對(duì)象,以及傳遞給包裝組件的任何props。

【注意】 errors, touched,status以及所有的事件處理器函數(shù)都沒(méi)有包含在FormikBag參數(shù)中。

validate?: (values: Values) => FormikErrors<Values> | Promise<any>

【注意】Formik作用特別推薦我們使用validationSchema和Yup實(shí)現(xiàn)表單校驗(yàn)。無(wú)論如何,表單校驗(yàn)應(yīng)該使用一種相對(duì)獨(dú)立的,比較直觀的方式實(shí)現(xiàn)——這也是每一個(gè)所希望的。

另外,你可以使用同步或者異步函數(shù)來(lái)實(shí)現(xiàn)表單校驗(yàn)。請(qǐng)參考下面的代碼:

(1)同步校驗(yàn)方式(返回一個(gè)errors對(duì)象)

// Synchronous validation
const validate = (values, props) => {
  let errors = {};

  if (!values.email) {
    errors.email = 'Required';
  } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
    errors.email = 'Invalid email address';
  }

  //...

  return errors;
};

(2)異步校驗(yàn)方式(返回errors對(duì)象中的一個(gè)代表錯(cuò)誤的Promise)

// Async Validation
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

const validate = (values, props) => {
  return sleep(2000).then(() => {
    let errors = {};
    if (['admin', 'null', 'god'].includes(values.username)) {
      errors.username = 'Nice try';
    }
    // ...
    if (Object.keys(errors).length) {
      throw errors;
    }
  });
};

validateOnBlur?: boolean

此屬性的默認(rèn)值為true。你可以在表單blur事件觸發(fā)時(shí)使用這個(gè)屬性——更具體一些說(shuō),無(wú)論是調(diào)用handleBlur,setFieldTouched還是setTouched都可以。

validateOnChange?: boolean

此屬性的默認(rèn)值為true。當(dāng)表單觸發(fā)change事件或者相關(guān)事件時(shí)你可以使用這個(gè)屬性告訴Formik進(jìn)行有關(guān)校驗(yàn)。 更具體一些說(shuō),無(wú)論是調(diào)用handleChange,setFieldValue還是setValues都可以。

validationSchema?: Schema | (() => Schema)

這個(gè)屬性非常重要,用于定義Yup模式( schema)或者是一個(gè)返回Yup模式的函數(shù),用于校驗(yàn)任務(wù)。其中,Errors會(huì)通過(guò)key映射到內(nèi)部組件的errors。這個(gè)屬性的keys應(yīng)當(dāng)與values中的相匹配。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI