Skip to content

Commit 50433fa

Browse files
committed
Implement field.onBlur in useField
1 parent f828d75 commit 50433fa

File tree

2 files changed

+32
-24
lines changed

2 files changed

+32
-24
lines changed

.changeset/wicked-goats-burn.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'formik': patch
3+
---
4+
5+
Implement useField field.onBlur to avoid rerendering entire form on blur events

packages/formik/src/useField.tsx

+27-24
Original file line numberDiff line numberDiff line change
@@ -109,16 +109,38 @@ export function useField<FieldValues = any>(
109109
const meta = useFieldMeta(fieldName);
110110
const { value: valueState, touched: touchedState } = meta;
111111
const setFieldValue = useFormikContextSelector(ctx => ctx.setFieldValue);
112-
const handleChange = useFormikContextSelector(ctx => ctx.handleChange);
113-
const handleBlur = useFormikContextSelector(ctx => ctx.handleBlur);
112+
const setFieldTouched = useFormikContextSelector(ctx => ctx.setFieldTouched);
114113
const getFieldHelpers = useFormikContextSelector(ctx => ctx.getFieldHelpers);
115114

116115
const field: FieldInputProps<any> = {
117116
name: fieldName,
118117
value: valueState,
119-
// @todo extract into factory methods to use between formik and field
120-
onChange: handleChange,
121-
onBlur: handleBlur,
118+
// We incorporate the fact that we know the `name` prop by scoping `onChange` and `onBlur`.
119+
// In addition, to support `parse` fn, we can't just re-use the OG `handleChange` and `handleBlur`, but
120+
// instead re-implement it's guts.
121+
onChange: (eventOrValue: React.ChangeEvent<any> | any) => {
122+
if (isInputEvent(eventOrValue)) {
123+
if (eventOrValue.persist) {
124+
eventOrValue.persist();
125+
}
126+
setFieldValue(
127+
fieldName,
128+
parse(getValueFromEvent(eventOrValue, valueState), fieldName)
129+
);
130+
} else {
131+
setFieldValue(fieldName, parse(eventOrValue, fieldName));
132+
}
133+
},
134+
onBlur: (eventOrValue: React.SyntheticEvent<any> | boolean) => {
135+
if (isInputEvent(eventOrValue)) {
136+
if (eventOrValue.persist) {
137+
eventOrValue.persist();
138+
}
139+
setFieldTouched(fieldName, true);
140+
} else {
141+
setFieldValue(fieldName, eventOrValue);
142+
}
143+
},
122144
};
123145

124146
const {
@@ -158,25 +180,6 @@ export function useField<FieldValues = any>(
158180
}
159181
}
160182

161-
// We incorporate the fact that we know the `name` prop by scoping `onChange`.
162-
// In addition, to support `parse` fn, we can't just re-use the OG `handleChange`, but
163-
// instead re-implement it's guts.
164-
if (type !== 'radio' && type !== 'checkbox') {
165-
field.onChange = (eventOrValue: React.ChangeEvent<any> | any) => {
166-
if (isInputEvent(eventOrValue)) {
167-
if (eventOrValue.persist) {
168-
eventOrValue.persist();
169-
}
170-
setFieldValue(
171-
fieldName,
172-
parse(getValueFromEvent(eventOrValue, valueState), fieldName)
173-
);
174-
} else {
175-
setFieldValue(fieldName, parse(eventOrValue, fieldName));
176-
}
177-
};
178-
}
179-
180183
return [field, meta, getFieldHelpers(fieldName)];
181184
}
182185

0 commit comments

Comments
 (0)