使用Formik轻松开发更高质量的React表单(四)其他几个API解析

(下面部分内容正处于翻译中,敬请稍等......)

<Field />

<Field /> will automagically hook up inputs to Formik. It uses the name attribute to match up with Formik state. <Field /> will default to an <input /> element. To change the underlying element of <Field />, specify a component prop. It can either be a string like select or another React component. <Field /> can also take a render prop.

import React from ‘react‘;
import { Formik, Field } from ‘formik‘;

const Example = () => (
  <div>
    <h1>My Form</h1>
    <Formik
      initialValues={{ email: ‘‘, color: ‘red‘, firstName: ‘‘ }}
      onSubmit={(values, actions) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          actions.setSubmitting(false);
        }, 1000);
      }}
      render={(props: FormikProps<Values>) => (
        <form onSubmit={props.handleSubmit}>
          <Field type="email" name="email" placeholder="Email" />
          <Field component="select" name="color">
            <option value="red">Red</option>
            <option value="green">Green</option>
            <option value="blue">Blue</option>
          </Field>
          <Field name="firstName" component={CustomInputComponent} />
          <Field
            name="lastName"
            render={({ field /* _form */ }) => (
              <input {...field} placeholder="firstName" />
            )}
          />
          <button type="submit">Submit</button>
        </form>
      )}
    />
  </div>
);

const CustomInputComponent: React.SFC<
  FieldProps<Values> & CustomInputProps
> = ({
  field, // { name, value, onChange, onBlur }
  form: { touched, errors }, // also values, setXXXX, handleXXXX, dirty, isValid, status, etc.
  ...props
}) => (
  <div>
    <input type="text" {...field} {...props} />
    {touched[field.name] &&
      errors[field.name] && <div className="error">{errors[field.name]}</div>}
  </div>
);

validate?: (value: any) => undefined | string | Promise<any>

You can run independent field-level validations by passing a function to the validate prop. The function will respect the validateOnBlur and validateOnChange config/props specified in the <Field>‘s parent <Formik> / withFormik. This function can be either be:

Synchronous and if invalid, return a string containing the error message or return undefined.

// Synchronous validation for Field
const validate = value => {
  let errorMessage;
  if (!/^[A-Z0-9._%+-][email protected][A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)) {
    errorMessage = ‘Invalid email address‘;
  }
  return errorMessage;
};

async: Return a Promise that throws a string containing the error message. This works like Formik‘s validate, but instead of returning an errors object, it‘s just a string.

Asynchronous and return a Promise that‘s error is an string with the error message

// Async validation for Field
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

const validate = value => {
  return sleep(2000).then(() => {
    if ([‘admin‘, ‘null‘, ‘god‘].includes(value)) {
      throw ‘Nice try‘;
    }
  });
};

Note: To allow for i18n libraries, the TypeScript typings for validate are slightly relaxed and allow you to return a Function (e.g. i18n(‘invalid‘)).

Refs

When you are not using a custom component and you need to access the underlying DOM node created by Field (e.g. to call focus), pass the callback to the innerRef prop instead.

<FieldArray />

<FieldArray /> is a component that helps with common array/list manipulations. You pass it a name property with the path to the key within values that holds the relevant array. <FieldArray /> will then give you access to array helper methods via render props. For convenience, calling these methods will trigger validation and also manage touched for you.

import React from ‘react‘;
import { Formik, Form, Field, FieldArray } from ‘formik‘;

// Here is an example of a form with an editable list.
// Next to each input are buttons for insert and remove.
// If the list is empty, there is a button to add an item.
export const FriendList = () => (
  <div>
    <h1>Friend List</h1>
    <Formik
      initialValues={{ friends: [‘jared‘, ‘ian‘, ‘brent‘] }}
      onSubmit={values =>
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
        }, 500)
      }
      render={({ values }) => (
        <Form>
          <FieldArray
            name="friends"
            render={arrayHelpers => (
              <div>
                {values.friends && values.friends.length > 0 ? (
                  values.friends.map((friend, index) => (
                    <div key={index}>
                      <Field name={`friends.${index}`} />
                      <button
                        type="button"
                        onClick={() => arrayHelpers.remove(index)} // remove a friend from the list
                      >
                        -
                      </button>
                      <button
                        type="button"
                        onClick={() => arrayHelpers.insert(index, ‘‘)} // insert an empty string at a position
                      >
                        +
                      </button>
                    </div>
                  ))
                ) : (
                  <button type="button" onClick={() => arrayHelpers.push(‘‘)}>
                    {/* show this when user has removed all friends from the list */}
                    Add a friend
                  </button>
                )}
                <div>
                  <button type="submit">Submit</button>
                </div>
              </div>
            )}
          />
        </Form>
      )}
    />
  </div>
);

name: string

The name or path to the relevant key in values.

validateOnChange?: boolean

Default is true. Determines if form validation should or should not be run after any array manipulations.

FieldArray Array of Objects

You can also iterate through an array of objects, by following a convention of object[index]property or object.index.property for the name attributes of <Field /> or <input /> elements in <FieldArray />.

<Form>
  <FieldArray
    name="friends"
    render={arrayHelpers => (
      <div>
        {values.friends.map((friend, index) => (
          <div key={index}>
            <Field name={`friends[${index}]name`} />
            <Field name={`friends.${index}.age`} /> // both these conventions do
            the same
            <button type="button" onClick={() => arrayHelpers.remove(index)}>
              -
            </button>
          </div>
        ))}
        <button
          type="button"
          onClick={() => arrayHelpers.push({ name: ‘‘, age: ‘‘ })}
        >
          +
        </button>
      </div>
    )}
  />
</Form>

FieldArray Validation Gotchas

Validation can be tricky with <FieldArray>.

If you use validationSchema and your form has array validation requirements (like a min length) as well as nested array field requirements, displaying errors can be tricky. Formik/Yup will show validation errors inside out. For example,

const schema = Yup.object().shape({
  friends: Yup.array()
    .of(
      Yup.object().shape({
        name: Yup.string()
          .min(4, ‘too short‘)
          .required(‘Required‘), // these constraints take precedence
        salary: Yup.string()
          .min(3, ‘cmon‘)
          .required(‘Required‘), // these constraints take precedence
      })
    )
    .required(‘Must have friends‘) // these constraints are shown if and only if inner constraints are satisfied
    .min(3, ‘Minimum of 3 friends‘),
});

Since Yup and your custom validation function should always output error messages as strings, you‘ll need to sniff whether your nested error is an array or a string when you go to display it.

So...to display ‘Must have friends‘ and ‘Minimum of 3 friends‘ (our example‘s array validation contstraints)...

Bad

// within a `FieldArray`‘s render
const FriendArrayErrors = errors =>
  errors.friends ? <div>{errors.friends}</div> : null; // app will crash

Good

// within a FieldArray‘s render

const FriendArrayErrors = errors =>
  typeof errors.friends === ‘string‘ ? <div>{errors.friends}</div> : null;

For the nested field errors, you should assume that no part of the object is defined unless you‘ve checked for it. Thus, you may want to do yourself a favor and make a custom <ErrorMessage /> component that looks like this:

import { Field, getIn } from ‘formik‘;

const ErrorMessage = ({ name }) => (
  <Field
    name={name}
    render={({ form }) => {
      const error = getIn(form.errors, name);
      const touch = getIn(form.touched, name);
      return touch && error ? error : null;
    }}
  />
);
// Usage
<ErrorMessage name="friends[0].name" />; // => null, ‘too short‘, or ‘required‘

NOTE: In Formik v0.12 / 1.0, a new meta prop may be added to Field and FieldArray that will give you relevant metadata such as error & touch, which will save you from having to use Formik or lodash‘s getIn or checking if the path is defined on your own.

FieldArray Helpers

The following methods are made available via render props.

  • push: (obj: any) => void: Add a value to the end of an array**
  • swap: (indexA: number, indexB: number) => void: Swap two values in an array
  • move: (from: number, to: number) => void: Move an element in an array to another index
  • insert: (index: number, value: any) => void: Insert an element at a given index into the array
  • unshift: (value: any) => number: Add an element to the beginning of an array and return its length
  • remove<T>(index: number): T | undefined: Remove an element at an index of an array and return it
  • pop<T>(): T | undefined: Remove and return value from the end of the array**

FieldArray render methods

There are three ways to render things with <FieldArray />

<FieldArray name="..." component>
<FieldArray name="..." render>
render: (arrayHelpers: ArrayHelpers) => React.ReactNode
import React from ‘react‘;
import { Formik, Form, Field, FieldArray } from ‘formik‘

export const FriendList = () => (
  <div>
    <h1>Friend List</h1>
    <Formik
      initialValues={{ friends: [‘jared‘, ‘ian‘, ‘brent‘] }}
      onSubmit={...}
      render={formikProps => (
        <FieldArray
          name="friends"
          render={({ move, swap, push, insert, unshift, pop }) => (
            <Form>
              {/*... use these however you want */}
            </Form>
          )}
        />
    />
  </div>
);

component: React.ReactNode

import React from ‘react‘;
import { Formik, Form, Field, FieldArray } from ‘formik‘

export const FriendList = () => (
  <div>
    <h1>Friend List</h1>
    <Formik
      initialValues={{ friends: [‘jared‘, ‘ian‘, ‘brent‘] }}
      onSubmit={...}
      render={formikProps => (
        <FieldArray
          name="friends"
          component={MyDynamicForm}
        />
    />
  </div>
);

// In addition to the array helpers, Formik state and helpers
// (values, touched, setXXX, etc) are provided through a `form`
// prop
export const MyDynamicForm = ({
  move, swap, push, insert, unshift, pop, form
}) => (
 <Form>
  {/**  whatever you need to do */}
 </Form>
);

<Form />




Like <Field />, <Form /> is a helper component you can use to save time. It is tiny wrapper around <form onSubmit={context.formik.handleSubmit} />. This means you don‘t need to explictly type out <form onSubmit={props.handleSubmit} /> if you don‘t want to.

ReactDOM only

import React from ‘react‘;
import { Formik, Field, Form } from ‘formik‘;

const Example = () => (
  <div>
    <h1>My Form</h1>
    <Formik
      initialValues={{ email: ‘‘, color: ‘red‘ }}
      onSubmit={(values, actions) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          actions.setSubmitting(false);
        }, 1000);
      }}
      component={MyForm}
    />
  </div>
);

const MyForm = () => (
  <Form>
    <Field type="email" name="email" placeholder="Email" />
    <Field component="select" name="color">
      <option value="red">Red</option>
      <option value="green">Green</option>
      <option value="blue">Blue</option>
    </Field>
    <button type="submit">Submit</button>
  </Form>
);

withFormik(options)

Create a higher-order React component class that passes props and form handlers (the "FormikBag") into your component derived from supplied options.

options

displayName?: string

When your inner form component is a stateless functional component, you can use the displayName option to give the component a proper name so you can more easily find it in React DevTools. If specified, your wrapped form will show up as Formik(displayName). If omitted, it will show up as Formik(Component). This option is not required for class components (e.g. class XXXXX extends React.Component {..}).

enableReinitialize?: boolean

Default is false. Control whether Formik should reset the form if the wrapped component props change (using deep equality).

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

Your form submission handler. It is passed your forms values and the "FormikBag", which includes an object containing a subset of the injected props and methods (i.e. all the methods with names that start with set<Thing> + resetForm) and any props that were passed to the the wrapped component.

The "FormikBag":
props (props passed to the wrapped component)
resetForm
setErrors
setFieldError
setFieldTouched
setFieldValue
setStatus
setSubmitting
setTouched
setValues
Note: errors, touched, status and all event handlers are NOT included in the FormikBag.

isInitialValid?: boolean | (props: Props) => boolean

Default is false. Control the initial value of isValid prop prior to mount. You can also pass a function. Useful for situations when you want to enable/disable a submit and reset buttons on initial mount.

mapPropsToValues?: (props: Props) => Values

If this option is specified, then Formik will transfer its results into updatable form state and make these values available to the new component as props.values. If mapPropsToValues is not specified, then Formik will map all props that are not functions to the inner component‘s props.values. That is, if you omit it, Formik will only pass props where typeof props[k] !== ‘function‘, where k is some key.

Even if your form is not receiving any props from its parent, use mapPropsToValues to initialize your forms empty state.

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

Note: I suggest using validationSchema and Yup for validation. However, validate is a dependency-free, straightforward way to validate your forms.

Validate the form‘s values with function. This function can either be:

Synchronous and return an errors object.
// Synchronous validation
const validate = (values, props) => {
  let errors = {};

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

  //...

  return errors;
};

Asynchronous and return a Promise that‘s error is an errors object

// 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

Default is true. Use this option to run validations on blur events. More specifically, when either handleBlur, setFieldTouched, or setTouched are called.

validateOnChange?: boolean

Default is true. Use this option to tell Formik to run validations on change events and change-related methods. More specifically, when either handleChange, setFieldValue, or setValues are called.

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

A Yup schema or a function that returns a Yup schema. This is used for validation. Errors are mapped by key to the inner component‘s errors. Its keys should match those of values.

Injected props and methods

These are identical to the props of <Formik render={props => ...} />

在Formik中使用connect()

connect()是一个高阶组件,that injects raw Formik context as prop called formik into the inner component. Fun fact: Formik uses connect() under the hood to wire up <Field/>, <FastField>, and <Form>. Advanced users may find it useful to use connect() when building custom components.

import { connect } from ‘formik‘;

const SubmitCount = ({ formik }) => <div>{formik.submitCount}</div>;

export default connect(SubmitCount);

原文地址:http://blog.51cto.com/zhuxianzhong/2152020

时间: 2024-10-28 20:18:33

使用Formik轻松开发更高质量的React表单(四)其他几个API解析的相关文章

使用Formik轻松开发更高质量的React表单(一)入门

前言 发现Formik是在我学习redux-form过程中从国外一篇博客上偶然发现的,看到作者的高度肯定后我立即转到github上,正如许多朋友所注意的,我发现其星数达8282,这个数字在github虽然不算很高,但是在探讨基于React技术开发跨平台表单这个主题的开源库角度来看,这个数字已经相当不错了.不自觉地,我对比了redux-form与Formik的几个数据,如下: 库 开源库的时间 星数 redux-form 3年以前 10210 Formik 1年前 8282 几个不太肯定的结论(欢

移动Web—CSS为Retina屏幕替换更高质量的图片

来源:互联网 作者:佚名 时间:12-24 10:37:45 [大 中 小] 点评:Retian似乎是屏幕显示的一种趋势,这也是Web设计师面对的一个新挑战;移动应用程序的设计师们已经学会了如何为Retina屏幕设备显示更好质量的图片,用来提高用户的体验;在本文中,你将看到如何使用CSS3技巧在Web应用中为Retina屏幕替换更高质量的图片 特别声明:此篇文章根据Stéphanie Walter 的英文文章<The Mobile Web: CSS Image Replacement for R

高质量的基于向量条形码产生机制 WPF Drawing API条形码控件

Barcode Professional for WPF条形码控件是一款轻量级的 .NET 程序集,为你的WPF程序生成高质量的基于矢量的条码,支持大多数流行的一维和二维条形码:Code 39, Code 128, GS1-128, GS1 DataBar (RSS-14),  EAN 13 & UPC, Postal (USPS, British Royal Mail, Australia Post, DHL, etc.), Data Matrix, QR Code, PDF 417, UPS

计算机专业如何高质量的走完大学四年?毕业成为Offer收割机

前言:迷茫本就是青春该有的模样,但不要让未来的你讨厌现在的自己. "就要毕业了. 回头看自己所谓的大学生活, 我想哭,不是因为离别,而是因为什么都没学到. 我不知,简历该怎么写,若是以往我会让它空白. 最大的收获也许是--对什么都没有的忍耐和适应--" 这是一个大四同学给李开复的信,这封来信道出了不少大三.大四学生的心声.大学期间,有许多学生放任自己.虚度光阴,还有许多学生始终也找不到正确的学习方向.当他们被第一次补考通知唤醒时,当他们收到第一封来自应聘企业的婉拒信时,这些学生才惊讶地

【jeecg移动开发能力】表单移动开发能力,提供多套表单模板(移动端、PC端),支持自定义

[一].请假表单风格(单表)  [1]移动端风格 [2]PC端风格一   [3]PC端风格二    [二].订单管理表单风格(一对多)  [1]移动端风格 [2]PC端风格一  [3]PC端风格二

通过FormData对象可以组装一组用 [XMLHttpRequest]发送请求的键/值对,它可以更灵活方便的发送表单数据。

工作记录用 1 大概页面,点击选择按钮,选择文件,填写备注并可以上传前预览,然后点击上传按钮开始上传 2 html+js代码 <h2>Test</h2> <div id="fileList"></div> <span id="file_ct" style="display:none"><input id="file_input" accept="Ima

基于vue开发的一款强大的表单设计器,支持element和antd-vue表单快速开发。

基于 vue 和 element-ui 实现的表单设计器,使用了最新的前端技术栈,内置了 i18n 国际化解决方案,支持生成element 和 antd-vue 表单,让表单开发简单而高效. 在线预览 使用文档 特性 可视化配置页面 提供栅格布局,并采用flex实现对齐 一键预览配置的效果 一键生成配置json数据 一键生成代码,立即可运行 提供自定义组件满足用户自定义需求 提供远端数据接口,方便用户需要异步获取数据加载 提供功能强大的高级组件 支持表单验证 快速获取表单数据 国际化支持 组件

编写高质量代码改善C#程序的157个建议——建议30:使用LINQ取代集合中的比较器和迭代器

建议30:使用LINQ取代集合中的比较器和迭代器 LINQ提供了类似于SQL的语法来实现遍历.筛选与投影集合的功能. static void Main(string[] args) { List<Salary> companySalary = new List<Salary>() { new Salary() { Name = "Mike", BaseSalary = 3000, Bonus = 1000 }, new Salary() { Name = &qu

企业站点如何做高质量的外链?腾讯分分彩官网

经常做外链的朋友都知道,外链难做.外链掉得快.外链质量低.网站得分也低,垃圾外链.黑链等问题.这些问题直接或是间接影响着网站的权重.那么企业又该如何做高质量的外链呢?我这里有几个建议,可解决企业站问题,供大家参考.(www.txfencai.com腾讯分分彩官网) 一.外链资源多样化,做为企业站.因为行业局限性,资源本来就少,在这种情况之下 就要多样化,注册几个B2B平台.博客平台.百度文库.百度贴吧.行业论坛等高权重的网站上发外链.减少被掉的风险. 二.用站群做外链,以站养站,重点是每个站都要