シナリオ
以下のようにして、Formik
のField
に自作のコンポーネントCustomField
を指定する場合。
import { Field, Form, FormikProps } from 'formik'
import * as React from 'react'
interface IFormValue {
custom: string
}
const CustomForm = React.memo<FormikProps<IFormValue>>(props => (
<Formik>
<Form>
<Field
name="custom"
component={CustomField}
setFieldValue={props.setFieldValue}
/>
</Form>
</Formik>
))
問題点
Formik (〜1.4.1)にはsetFieldValue()を呼び出してフィールドの値をセットすると、<Formik></Formik>
内の全てのフィールドが再描写されてしまう問題があるようです。入力の度に全てのフィールドが再描写されないようにするには以下のようにstate管理をする必要があります。
1. state
をprops.field.value
で初期化する。
interface ICustomFieldProps {
setFieldValue: (name: string, value: string) => void
}
interface ICustomFieldState {
value: string
}
class CustomField extends React.Component<ICustomFieldProps, ICustomFieldState> {
public state: ICustomFieldState = { value: this.props.field.value }
...
}
2. onChange
ではstate.value
のみを更新する。
private handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({
value: event.currentTarget.value
})
}
3. onBlur
でprops.field.value
を更新する。
private handleBlur = (event: React.ChangeEvent<HTMLInputElement>) => {
this.props.setFieldValue(
this.props.field.name,
event.currentTarget.value
)
}
4. shouldComponentUpdate
でprops.field.valueとstate.value
を比較して値が異なる場合のみtrueを返す。
public shouldComponentUpdate(
nextProps: IFieldProps,
nextState: IFieldState
) {
return nextProps.field.value !== nextState.value
}