From a0b18dc6902c04d29457e659526454c761e6dada Mon Sep 17 00:00:00 2001 From: Matthew McLeod Date: Sat, 24 Aug 2019 23:10:34 -0400 Subject: [PATCH 1/4] Introduce useFastField --- docs/api/useFastField.md | 83 ++++++++++++++++++++++++++++++++++++++++ src/Field.tsx | 21 ++++++++++ website/sidebars.json | 23 +++++++++-- 3 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 docs/api/useFastField.md diff --git a/docs/api/useFastField.md b/docs/api/useFastField.md new file mode 100644 index 000000000..2555d6844 --- /dev/null +++ b/docs/api/useFastField.md @@ -0,0 +1,83 @@ +--- +id: useFastField +title: useFastField() +custom_edit_url: https://github.com/jaredpalmer/formik/edit/master/docs/api/useFastField.md +--- + +`useFastField` is a custom React hook that will automagically help you hook up inputs in a similar way to `useField`. +The useFastField behaviour imitates `useField` when Formik is configured to validate onBlur. The Formik values model is not updated after an onChange event only the input field is updated. After an onBlur event, the Formik values and error model are all update resulting in some minor behaviour variations. There are 2 ways to use it. + +## Example + +```tsx +import React from 'react'; +import { useFastField, Formik } from 'formik'; + +const MyTextField = ({ label, ...props }) => { + const [field, meta] = useFastField(props.name); + return ( + <> + + {meta.touched && meta.error ? ( +
{meta.error}
+ ) : null} + + ); +}; + +const Example = () => ( +
+

My Form

+ { + setTimeout(() => { + alert(JSON.stringify(values, null, 2)); + actions.setSubmitting(false); + }, 1000); + }} + render={(props: FormikProps) => ( +
+ + + + + + )} + /> +
+); +``` + +--- + +# Reference + +## `useFastField(name: string): [FieldInputProps, FieldMetaProps]` + +A custom React Hook that returns a tuple (2 element array) containing `FieldProps` and `FieldMetaProps`. + +### `FieldInputProps` + +An object that contains: + +- `name: string` - The name of the field +- `onBlur: () => void;` - A blur event handler +- `onChange: (e: React.ChangeEvent) => void` - A change event handler +- `value: any` - The field's value (plucked out of `values`) + +for a given field in Formik state. This is to avoid needing to manually wire up inputs. + +### `FieldMetaProps` + +An object that contains relevant computed metadata about a field. More specifically, + +- `error?: string` - The field's error message (plucked out of `errors`) +- `initialError?: string` - The field's initial error if the field is present in `initialErrors` (plucked out of `initialErrors`) +- `initialTouched: boolean` - The field's initial value if the field is present in `initialTouched` (plucked out of `initialTouched`) +- `initialValue?: any` - The field's initial value if the field is given a value in `initialValues` (plucked out of `initialValues`) +- `touched: boolean` - Whether the field has been visited (plucked out of `touched`) +- `value: any` - The field's value (plucked out of `values`) diff --git a/src/Field.tsx b/src/Field.tsx index e2fe1e830..dc884c777 100644 --- a/src/Field.tsx +++ b/src/Field.tsx @@ -92,6 +92,27 @@ export function useField( return formik.getFieldProps({ name: propsOrFieldName }); } +export function useFastField

( + props: FieldAttributes

+): [FieldInputProps

, FieldMetaProps

] { + const [field, meta] = useField

(props); + const [value, setValue] = React.useState

(field.value); + const { onBlur, onChange } = field; + + field.value = value; + field.onChange = (e: any): void => { + if (e && e.currentTarget) { + setValue(e.currentTarget.value); + } + }; + field.onBlur = (e: any): void => { + onChange(e); + onBlur(e); + }; + + return [field, meta]; +} + export function Field({ validate, name, diff --git a/website/sidebars.json b/website/sidebars.json index 1b0f8a7b1..a3ca76b34 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -1,7 +1,24 @@ { "docs": { "Getting Started": ["overview", "tutorial", "resources"], - "Guides": ["guides/validation", "guides/arrays", "guides/typescript", "guides/react-native", "guides/form-submission"], - "API Reference": ["api/formik", "api/withFormik", "api/field", "api/usefield", "api/fieldarray", "api/form", "api/errormessage", "api/connect", "api/fastfield"] + "Guides": [ + "guides/validation", + "guides/arrays", + "guides/typescript", + "guides/react-native", + "guides/form-submission" + ], + "API Reference": [ + "api/formik", + "api/withFormik", + "api/field", + "api/usefield", + "api/usefastfield", + "api/fieldarray", + "api/form", + "api/errormessage", + "api/connect", + "api/fastfield" + ] } -} \ No newline at end of file +} From 211978411fc4aec61c397b78cddf594bede0d647 Mon Sep 17 00:00:00 2001 From: Matthew McLeod Date: Sat, 24 Aug 2019 23:22:46 -0400 Subject: [PATCH 2/4] Improve docs --- docs/api/useFastField.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/useFastField.md b/docs/api/useFastField.md index 2555d6844..e9c67046e 100644 --- a/docs/api/useFastField.md +++ b/docs/api/useFastField.md @@ -5,7 +5,7 @@ custom_edit_url: https://github.com/jaredpalmer/formik/edit/master/docs/api/useF --- `useFastField` is a custom React hook that will automagically help you hook up inputs in a similar way to `useField`. -The useFastField behaviour imitates `useField` when Formik is configured to validate onBlur. The Formik values model is not updated after an onChange event only the input field is updated. After an onBlur event, the Formik values and error model are all update resulting in some minor behaviour variations. There are 2 ways to use it. +The `useFastField` behaviour imitates `useField` when Formik is configured to validate onBlur. The Formik model is not updated after an onChange event, only the input field is updated. After an onBlur event occurs, the Formik v model is updated resulting in a more performant way at the expense of some minor differences. There are 2 ways to use it. ## Example From debb7a467a0b5d3311f7b05a6ff56b3cfc6411ed Mon Sep 17 00:00:00 2001 From: Matthew McLeod Date: Sun, 25 Aug 2019 00:09:12 -0400 Subject: [PATCH 3/4] Update docs to next --- docs/api/useFastField.md | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/api/useFastField.md b/docs/api/useFastField.md index e9c67046e..b49eb9c6e 100644 --- a/docs/api/useFastField.md +++ b/docs/api/useFastField.md @@ -58,16 +58,45 @@ const Example = () => ( ## `useFastField(name: string): [FieldInputProps, FieldMetaProps]` -A custom React Hook that returns a tuple (2 element array) containing `FieldProps` and `FieldMetaProps`. +A custom React Hook that returns a tuple (2 element array) containing `FieldProps` and `FieldMetaProps`. It accepts either a string of a field name or an object as an argument. The object must at least contain a `name` key. This object should identical to the props that you would pass to `` and the returned helpers will imitate the behavior of ``. This is useful, and generally preferred, since it allows you to take advantage of formik's checkbox, radio, and multiple select behavior when the object contains the relevant key/values (e.g. `type: 'checkbox'`, `multiple: true`, etc.). + +```jsx +import React from 'react'; +import { useFastField } from 'formik'; + +function MyTextField(props) { + // this will return field props for an + const [field, meta] = useFastField(props.name); + return ( + <> + + {meta.error && meta.touched &&

{meta.error}
} + + ); +} + +function MyInput(props) { + // this will return field exactly like {({ field }) => ... } + const [field, meta] = useFastField(props); + return ( + <> + + {meta.error && meta.touched &&
{meta.error}
} + + ); +} +``` ### `FieldInputProps` An object that contains: - `name: string` - The name of the field +- `checked?: boolean` - Whether or not the input is checked, this is only defined if `useField` is passed an object with a `name`, `type: "checkbox"` or `type: radio`. - `onBlur: () => void;` - A blur event handler - `onChange: (e: React.ChangeEvent) => void` - A change event handler -- `value: any` - The field's value (plucked out of `values`) +- `value: any` - The field's value (plucked out of `values`) or, if it is a checkbox or radio input, then potentially the `value` passed into `useField`. +- `multiple?: boolean` - Whether or not the multiple values can be selected. This is only ever defined when `useField` is passed an object with `multiple: true` for a given field in Formik state. This is to avoid needing to manually wire up inputs. From 4101827e306b2da4ac3f4b6dfd276fc2297f045c Mon Sep 17 00:00:00 2001 From: Matthew McLeod Date: Sun, 25 Aug 2019 00:11:30 -0400 Subject: [PATCH 4/4] Change type to Val for consistency --- src/Field.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Field.tsx b/src/Field.tsx index dc884c777..3354d7cfc 100644 --- a/src/Field.tsx +++ b/src/Field.tsx @@ -92,11 +92,11 @@ export function useField( return formik.getFieldProps({ name: propsOrFieldName }); } -export function useFastField

( - props: FieldAttributes

-): [FieldInputProps

, FieldMetaProps

] { - const [field, meta] = useField

(props); - const [value, setValue] = React.useState

(field.value); +export function useFastField( + props: FieldAttributes +): [FieldInputProps, FieldMetaProps] { + const [field, meta] = useField(props); + const [value, setValue] = React.useState(field.value); const { onBlur, onChange } = field; field.value = value;