94 lines
3.1 KiB
TypeScript
94 lines
3.1 KiB
TypeScript
// Render Prop
|
|
import React from 'react';
|
|
import { Formik, FormikErrors } from 'formik';
|
|
|
|
type MyData = {email: string, password: string};
|
|
declare function LoginToMyApp(data: MyData): Promise<{user: string}>;
|
|
declare function transformMyApiErrors(o: any): FormikErrors<never>;
|
|
|
|
const Basic = () => (
|
|
<div>
|
|
<h1>My Form</h1>
|
|
<p>This can be anywhere in your application</p>
|
|
{/*
|
|
The benefit of the render prop approach is that you have full access to React's
|
|
state, props, and composition model. Thus there is no need to map outer props
|
|
to values...you can just set the initial values, and if they depend on props / state
|
|
then--boom--you can directly access to props / state.
|
|
|
|
The render prop accepts your inner form component, which you can define separately or inline
|
|
totally up to you:
|
|
- `<Formik render={props => <form>...</form>}>`
|
|
- `<Formik component={InnerForm}>`
|
|
- `<Formik>{props => <form>...</form>}</Formik>` (identical to as render, just written differently)
|
|
*/}
|
|
<Formik
|
|
initialValues={{
|
|
email: '',
|
|
password: '',
|
|
}}
|
|
validate={values => {
|
|
// same as above, but feel free to move this into a class method now.
|
|
let errors: FormikErrors<MyData> = {} as FormikErrors<MyData>; // FormikErrors<MyData> isn't optionalized, so in strict null checks this needs a cast
|
|
if (!values.email) {
|
|
errors.email = 'Required';
|
|
} else if (
|
|
!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)
|
|
) {
|
|
errors.email = 'Invalid email address';
|
|
}
|
|
return errors;
|
|
}}
|
|
onSubmit={(
|
|
values,
|
|
{ setSubmitting, setErrors /* setValues and other goodies */ }
|
|
) => {
|
|
LoginToMyApp(values).then(
|
|
user => {
|
|
setSubmitting(false);
|
|
// do whatevs...
|
|
// props.updateUser(user)
|
|
},
|
|
errors => {
|
|
setSubmitting(false);
|
|
// Maybe transform your API's errors into the same shape as Formik's
|
|
setErrors(transformMyApiErrors(errors));
|
|
}
|
|
);
|
|
}}
|
|
render={({
|
|
values,
|
|
errors,
|
|
touched,
|
|
handleChange,
|
|
handleBlur,
|
|
handleSubmit,
|
|
isSubmitting,
|
|
}) => (
|
|
<form onSubmit={handleSubmit}>
|
|
<input
|
|
type="email"
|
|
name="email"
|
|
onChange={handleChange}
|
|
onBlur={handleBlur}
|
|
value={values.email}
|
|
/>
|
|
{touched.email && errors.email && <div>{errors.email}</div>}
|
|
<input
|
|
type="password"
|
|
name="password"
|
|
onChange={handleChange}
|
|
onBlur={handleBlur}
|
|
value={values.password}
|
|
/>
|
|
{touched.password && errors.password && <div>{errors.password}</div>}
|
|
<button type="submit" disabled={isSubmitting}>
|
|
Submit
|
|
</button>
|
|
</form>
|
|
)}
|
|
/>
|
|
</div>
|
|
);
|
|
|
|
export default Basic; |