溫馨提示×

溫馨提示×

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

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用Formik輕松開發(fā)更高質(zhì)量的React表單(一)入門

發(fā)布時間:2020-06-20 02:05:11 來源:網(wǎng)絡 閱讀:4566 作者:googlingman 欄目:web開發(fā)

使用Formik輕松開發(fā)更高質(zhì)量的React表單(一)入門

前言


發(fā)現(xiàn)Formik是在我學習redux-form過程中從國外一篇博客上偶然發(fā)現(xiàn)的,看到作者的高度肯定后我立即轉(zhuǎn)到github上,正如許多朋友所關注的,F(xiàn)ormik的星數(shù)達8282,這個數(shù)字在github雖然不算很高,但是從基于React技術跨平臺表單開發(fā)這個主題角度來看,此數(shù)字已經(jīng)相當可觀了。不自覺地,我對比了redux-form與Formik的幾個數(shù)據(jù),如下:

開源庫的時間 星數(shù)
redux-form 3年以前 10210
Formik 1年前 8282

于是,我得出如下幾個不太肯定的結(jié)論(歡迎有興趣的朋友一起討論):


1,redux-form是目前基于React+Redux開發(fā)構(gòu)建表單子項目時主要開源選擇方案;
2,redux-form很可能是目前大多數(shù)React程序員心目中高效解決方案的選擇;
3,在github上Formik在未來一年后星數(shù)很有可能會超過redux-form項目。


我作出上述猜測主要理由是,經(jīng)過這段時間我redux-form學習,我發(fā)現(xiàn)要深度掌握redux-form實踐應用并靈活地處理各種有關問題,需要花費相當?shù)拇鷥r。尤其說明問題的是,在表單體積膨脹和數(shù)量急劇增加的情況下,系統(tǒng)的性能有可能受到嚴重的影響?,F(xiàn)在我有了react-redux基礎,并理解了redux-form應用原理后,感覺使用Formik開發(fā)React表單一下變得異常輕松愉快!

為了節(jié)約時間,本系列的幾篇我會首先使用英語方式,再在后面的時間里逐篇翻譯成中文。

為什么不直接用Redux-Form?


至此,你可能會想:“為什么不使用Redux-Form這一方案呢?”對于這個問題,包括我在內(nèi)的Redux用戶都會自然地提出這個問題。對此,F(xiàn)ormik開發(fā)者的列出如下三個理由:


**1. React開發(fā)專家Dan Abramov認為,表單狀態(tài)本質(zhì)上是短暫的和局部性的,因此通過Redux解決方案(或任何類型的Flux庫)來跟蹤表單狀態(tài)是不必要的。

  1. Redux-Form往往針對每一次用戶擊鍵多次調(diào)用前端系統(tǒng)頂層的Redux reducer。對于小應用來說,這還算可以;但是,隨著你的Redux應用程序的不斷增長,輸入要求很可能會急劇膨脹——如果你使用Redux-Form作為前端表單解決方案的話。
  2. Redux-Form經(jīng)壓縮打包后的大小為22.5 kB,而Formik的大小為7.8 kB。**

Formik的開發(fā)目標是:使用最小的易于使用的API調(diào)用創(chuàng)建一個可伸縮的、持久性的表單生成器。當然,還提供另外一些功能供開發(fā)者定制使用。

靈感來源


Formik受到Brent Jackson開發(fā)的高階組件的啟發(fā) 。同時還吸收了Redux-Form庫的命名方案;還有受到React-Motion和React-Router 4的啟發(fā)最新引入的render屬性。無論你是否使用過上述這些庫,F(xiàn)ormik 都會使你在短短的數(shù)分鐘內(nèi)快速入門。

安裝

把Formik添加到你的已有項目中的方式如下:

npm i formik --save

示例

官方網(wǎng)站上提供了一組類似于redux-form官方的示例供初學者學習之用。它們有:

  • 基本類型示例
  • 同步校驗示例
  • 開發(fā)自己的輸入原型
  • 與react-select聯(lián)合應用
  • 與Draft.js聯(lián)合應用
  • 訪問React生命周期函數(shù)
  • 在React Native開發(fā)中的應用

Formik的核心

Formik跟蹤表單狀態(tài),然后以props方式把此狀態(tài)還有一些可重用的方法和事件處理器(例如 handleChange,handleBlur和handleSubmit暴露給表單組件。其中,handleChange 和handleBlur工作方式完全一樣——都使用name或者id屬性來標記要更新的表單字段。
歸納來看,可以使用如下兩種方式之一來使用Formik:


  • withFormik():一個高階組件(HoC),它接收一個配置對象作為參數(shù);
  • <Formik />:這是一個React組件,它提供了一個名稱為render的屬性。

上述兩種方式完全一樣工作,內(nèi)部實現(xiàn)原理完全相同。只是各自在使用風格上有所不同而已。請參考如下代碼:

//高階組件方式
import React from 'react';
import { withFormik } from 'formik';

// Our inner form component which receives our form's state and updater methods as props
const InnerForm = ({
  values,
  errors,
  touched,
  handleChange,
  handleBlur,
  handleSubmit,
  isSubmitting,
}) => (
  <form onSubmit={handleSubmit}>
    <input
      type="email"
      name="email"
      onChange={handleChange}
      onBlur={handleBlur}
      value={values.email}
    />
    {touched.email && errors.email && <div>{errors.email}</div>}
    <input
      type="password"
      name="password"
      onChange={handleChange}
      onBlur={handleBlur}
      value={values.password}
    />
    {touched.password && errors.password && <div>{errors.password}</div>}
    <button type="submit" disabled={isSubmitting}>
      Submit
    </button>
  </form>
);

//使用withFormik HoC包裝表單
const MyForm = withFormik({
  // Transform outer props into form values
  mapPropsToValues: props => ({ email: '', password: '' }),
  // Add a custom validation function (this can be async too!)
  validate: (values, props) => {
    const 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;
  },
  //表單提交處理器
  handleSubmit: (
    values,
    {
      props,
      setSubmitting,
      setErrors /* setValues, setStatus, and other goodies */,
    }
  ) => {
    LoginToMyApp(values).then(
      user => {
        setSubmitting(false);
        // do whatevs...
        // props.updateUser(user)
      },
      errors => {
        setSubmitting(false);
        // Maybe even transform your API's errors into the same shape as Formik's!
        setErrors(transformMyApiErrors(errors));
      }
    );
  },
})(InnerForm);

//然后你可以在任何地方自由使用<MyForm />組件
const Basic = () => (
  <div>
    <h2>My Form</h2>
    <p>This can be anywhere in your application</p>
    <MyForm />
  </div>
);

export default Basic;
// Render Prop
import React from 'react';
import { Formik } from 'formik';

const Basic = () => (
  <div>
    <h2>My Form</h2>
    <p>This can be anywhere in your application</p>
    {/*
          The benefit of the render prop approach is that you have full access to React's
          state, props, and composition model. Thus there is no need to map outer props
          to values...you can just set the initial values, and if they depend on props / state
          then--boom--you can directly access to props / state.
          The render prop accepts your inner form component, which you can define separately or inline
          totally up to you:
          - `<Formik render={props => <form>...</form>}>`
          - `<Formik component={InnerForm}>`
          - `<Formik>{props => <form>...</form>}</Formik>` (identical to as render, just written differently)
        */}
    <Formik
      initialValues={{
        email: '',
        password: '',
      }}
      validate={values => {
        // same as above, but feel free to move this into a class method now.
        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;
      }}
      onSubmit={(
        values,
        { setSubmitting, setErrors /* setValues and other goodies */ }
      ) => {
        LoginToMyApp(values).then(
          user => {
            setSubmitting(false);
            // do whatevs...
            // props.updateUser(user)
          },
          errors => {
            setSubmitting(false);
            // Maybe transform your API's errors into the same shape as Formik's
            setErrors(transformMyApiErrors(errors));
          }
        );
      }}
      render={({
        values,
        errors,
        touched,
        handleChange,
        handleBlur,
        handleSubmit,
        isSubmitting,
      }) => (
        <form onSubmit={handleSubmit}>
          <input
            type="email"
            name="email"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.email}
          />
          {touched.email && errors.email && <div>{errors.email}</div>}
          <input
            type="password"
            name="password"
            onChange={handleChange}
            onBlur={handleBlur}
            value={values.password}
          />
          {touched.password && errors.password && <div>{errors.password}</div>}
          <button type="submit" disabled={isSubmitting}>
            Submit
          </button>
        </form>
      )}
    />
  </div>
);

export default Basic;

補充說明

正你從上面觀察到的,表單的校驗邏輯完全由開發(fā)者自己實現(xiàn)。你可以心情使用第三方庫來編寫你自己的定制校驗器。從官方網(wǎng)站上了解到,示例中大量使用Yup庫來實現(xiàn)對象的格式校驗。它提供了一種十分類似于Joi / React PropTypes的API,只不過在瀏覽器中尺寸十分小巧,且對運行時應用來說已經(jīng)足夠快。在此建議同學們也積極使用Yup。并且在Formik中也針對Yup提供了一種特別的配置選項/屬性稱作validationSchema,它能夠把Yup的校驗錯誤自動轉(zhuǎn)換成一種很小的對象(對象中也提供了values和touched等鍵支持)。使用npm把Yup安裝到你的項目中的方式如下:

npm install yup --save

參考資料

1.https://github.com/jaredpalmer/formik
2.http://www.lizhe.name/node/252
3.https://keyholesoftware.com/2017/10/23/the-joy-of-forms-with-react-and-formik/

向AI問一下細節(jié)

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

AI