從 v1.x 遷移到 v2.x

重大變更

最低需求

  • 由於 Formik 2 建立在 React Hooks 之上,您必須使用 React 16.8.x 或更高版本
  • 由於 Formik 2 使用 unknown 類型,您必須使用 TypeScript 3.0 或更高版本(如果您使用 TypeScript)

Formik 2.x 中有一些重大變更。幸運的是,這些變更可能不會影響太多人

resetForm

在 Formik 2 中,我們引入了新的屬性以獲得更多初始狀態:initialErrorsinitialTouchedinitialStatus。因此,resetForm 的簽名已更改。它不再僅選擇性地接受表單的下一個初始值。現在,它選擇性地接受 Formik 的部分下一個初始狀態。

v1

// Reset to `initialValues`
formik.resetForm();
// Reset form and set the next `initialValues` of the form
formik.resetForm({ name: '', email: '' });

v2

// Reset the form. This will set the next initial state of
// Formik to the `initialValues`, `initialErrors`, `initialTouched`,
// `initialStatus` props.
formik.resetForm();
// Reset the form back to `initialXXXX` but change next
// `initialValues` to a custom value
formik.resetForm({
values: { name: 'Custom initial values', email: '' },
});
// Reset form back to `initialXXXX`, but change next `initialValues`
// and `initialErrors` of the form
formik.resetForm({
values: { name: '', email: '' },
errors: { name: 'Something special' },
});
// Reset form back to `initialXXXX`, but change next `initialStatus` to 'Foo'
formik.resetForm({
status: 'Foo',
});

setError

此方法在 v1.x 版本中已棄用一段時間,並發出警告。它在 v2 中已完全移除。請改用 Formik 的 setStatus(status)。它的功能相同。注意:這不是/不是 setErrors(複數),它仍然存在。

validate

您可能知道,您可以從 validate 返回驗證錯誤的 Promise。在 1.x 中,此 promise 是 resolved 還是 rejected 無關緊要,因為在這兩種情況下,promise 的有效負載都被解釋為驗證錯誤。在 2.x 中,拒絕將被解釋為實際的例外,並且它不會更新表單錯誤狀態。任何返回 rejected promise 錯誤的驗證函數都需要調整為返回 resolved promise 錯誤。

ref

目前,您無法使用 ref 屬性將 ref 附加到 Formik。但是,您仍然可以使用屬性 innerRef 解決此問題。我們有一些正在進行中的工作 #2208 來改用 React.forwardRef

isValid

此屬性不再考慮 dirty 的值。這表示如果您想在表單不是 dirty 時停用提交按鈕(即第一次渲染以及值未更改時),您必須明確檢查它。

<button disabled={!isValid || !dirty} type="submit">
Submit
</button>

Typescript 變更

FormikActions

FormikActions 已重新命名為 FormikHelpers 導入或別名類型應該是一個簡單的更改

v1

import { FormikActions } from 'formik';

v2

import { FormikHelpers as FormikActions } from 'formik';

FieldProps

FieldProps 現在接受兩個泛型類型參數。 兩個參數都是可選的,但 FormValues 已從第一個參數移至第二個參數。

v1

type Props = FieldProps<FormValues>;

v2

type Props = FieldProps<FieldValue, FormValues>;

新增功能?

核取方塊和多選

與 Angular、Vue 或 Svelte 類似,Formik 2 通過內建的陣列繫結和布林行為“修復”了 React 核取方塊和多選。這是 Formik 1.x 中人們最困惑的事情之一。

import React from 'react';
import { Formik, Field, Form } from 'formik';
import { Debug } from './Debug';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const CheckboxExample = () => (
<div>
<h1>Checkboxes</h1>
<p>
This example demonstrates how to properly create checkboxes with Formik.
</p>
<Formik
initialValues={{
isAwesome: false,
terms: false,
newsletter: false,
jobType: ['designer'],
location: [],
}}
onSubmit={async values => {
await sleep(1000);
alert(JSON.stringify(values, null, 2));
}}
>
{({ isSubmitting, getFieldProps, handleChange, handleBlur, values }) => (
<Form>
{/*
This first checkbox will result in a boolean value being stored.
*/}
<div className="label">Basic Info</div>
<label>
<Field type="checkbox" name="isAwesome" />
Are you awesome?
</label>
{/*
Multiple checkboxes with the same name attribute, but different
value attributes will be considered a "checkbox group". Formik will automagically
bind the checked values to a single array for your benefit. All the add and remove
logic will be taken care of for you.
*/}
<div className="label">
What best describes you? (check all that apply)
</div>
<label>
<Field type="checkbox" name="jobType" value="designer" />
Designer
</label>
<label>
<Field type="checkbox" name="jobType" value="developer" />
Developer
</label>
<label>
<Field type="checkbox" name="jobType" value="product" />
Product Manager
</label>
{/*
You do not _need_ to use <Field>/useField to get this behavior,
using handleChange, handleBlur, and values works as well.
*/}
<label>
<input
type="checkbox"
name="jobType"
value="founder"
checked={values.jobType.includes('founder')}
onChange={handleChange}
onBlur={handleBlur}
/>
CEO / Founder
</label>
{/*
The <select> element will also behave the same way if
you pass `multiple` prop to it.
*/}
<label htmlFor="location">Where do you work?</label>
<Field
component="select"
id="location"
name="location"
multiple={true}
>
<option value="NY">New York</option>
<option value="SF">San Francisco</option>
<option value="CH">Chicago</option>
<option value="OTHER">Other</option>
</Field>
<label>
<Field type="checkbox" name="terms" />I accept the terms and
conditions.
</label>
{/* Here's how you can use a checkbox to show / hide another field */}
{!!values.terms ? (
<div>
<label>
<Field type="checkbox" name="newsletter" />
Send me the newsletter <em style={{ color: 'rebeccapurple' }}>
(This is only shown if terms = true)
</em>
</label>
</div>
) : null}
<button type="submit" disabled={isSubmitting}>
Submit
</button>
<Debug />
</Form>
)}
</Formik>
</div>
);
export default CheckboxExample;

useField()

正如您所想的,它就像 <Field>,但帶有一個 hook。有關用法,請參閱文件。

useFormikContext()

等效於 connect() 的 hook。

<Field as>

<Field/> 現在接受一個名為 as 的屬性,它將直接將 onChangeonBlurvalue 等注入到組件或字串中。這對於使用 Emotion 或 Styled 組件的人很有用,因為他們不再需要在包裝函數中清理 component 的渲染屬性。

// <input className="form-input" placeholder="Jane" />
<Field name="firstName" className="form-input" placeholder="Jane" />
// <textarea className="form-textarea"/></textarea>
<Field name="message" as="textarea" className="form-textarea"/>
// <select className="my-select"/>
<Field name="colors" as="select" className="my-select">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</Field>
// with styled-components/emotion
const MyStyledInput = styled.input`
padding: .5em;
border: 1px solid #eee;
/* ... */
`
const MyStyledTextarea = MyStyledInput.withComponent('textarea');
// <input className="czx_123" placeholder="google.com" />
<Field name="website" as={MyStyledInput} placeholder="google.com"/>
// <textarea placeholder="Post a message..." rows={5}></textarea>
<Field name="message" as={MyStyledTextArea} placeholder="Post a message.." rows={4}/>

getFieldProps(nameOrProps)

FormikProps 有兩個有用的新增功能,getFieldPropsgetFieldMeta。這些是 Kent C. Dodds 風格的屬性 getter,如果您喜歡屬性鑽取、*不*使用基於上下文的 API 或正在構建自定義 useField,則它們會很有用。

export interface FieldInputProps<Value> {
/** Value of the field */
value: Value;
/** Name of the field */
name: string;
/** Multiple select? */
multiple?: boolean;
/** Is the field checked? */
checked?: boolean;
/** Change event handler */
onChange: FormikHandlers['handleChange'];
/** Blur event handler */
onBlur: FormikHandlers['handleBlur'];
}

getFieldMeta(name)

給定一個名稱,它將返回一個物件

export interface FieldMetaProps<Value> {
/** Value of the field */
value: Value;
/** Error message of the field */
error?: string;
/** Has the field been visited? */
touched: boolean;
/** Initial value of the field */
initialValue?: Value;
/** Initial touched state of the field */
initialTouched: boolean;
/** Initial error message of the field */
initialError?: string;
}

其他

  • 現在導出 FormikContext
  • validateOnMount?: boolean = false
  • 已新增 initialErrorsinitialTouchedinitialStatus

棄用警告

所有 render 屬性都已棄用,並發出控制台警告。

對於 <Field><FastField><Formik><FieldArray>render 屬性已棄用並發出警告,因為它將在 zukünftigen 版本中移除。請改用子回調函數。此棄用旨在與 React Context Consumer 的用法平行。

- <Field name="firstName" render={props => ....} />
+ <Field name="firstName">{props => ... }</Field>
這個頁面有幫助嗎?

訂閱我們的電子報

最新的 Formik 新聞、文章和資源,將發送到您的收件匣。

版權所有 © 2020 Formium, Inc. 保留一切權利。