• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Render Prop
2import React from 'react';
3import { Formik, FormikErrors } from 'formik';
4
5type MyData = {email: string, password: string};
6declare function LoginToMyApp(data: MyData): Promise<{user: string}>;
7declare function transformMyApiErrors(o: any): FormikErrors<never>;
8
9const Basic = () => (
10  <div>
11    <h1>My Form</h1>
12    <p>This can be anywhere in your application</p>
13    {/*
14      The benefit of the render prop approach is that you have full access to React's
15      state, props, and composition model. Thus there is no need to map outer props
16      to values...you can just set the initial values, and if they depend on props / state
17      then--boom--you can directly access to props / state.
18
19      The render prop accepts your inner form component, which you can define separately or inline
20      totally up to you:
21      - `<Formik render={props => <form>...</form>}>`
22      - `<Formik component={InnerForm}>`
23      - `<Formik>{props => <form>...</form>}</Formik>` (identical to as render, just written differently)
24    */}
25    <Formik
26      initialValues={{
27        email: '',
28        password: '',
29      }}
30      validate={values => {
31        // same as above, but feel free to move this into a class method now.
32        let errors: FormikErrors<MyData> = {} as FormikErrors<MyData>; // FormikErrors<MyData> isn't optionalized, so in strict null checks this needs a cast
33        if (!values.email) {
34          errors.email = 'Required';
35        } else if (
36          !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)
37        ) {
38          errors.email = 'Invalid email address';
39        }
40        return errors;
41      }}
42      onSubmit={(
43        values,
44        { setSubmitting, setErrors /* setValues and other goodies */ }
45      ) => {
46        LoginToMyApp(values).then(
47          user => {
48            setSubmitting(false);
49            // do whatevs...
50            // props.updateUser(user)
51          },
52          errors => {
53            setSubmitting(false);
54            // Maybe transform your API's errors into the same shape as Formik's
55            setErrors(transformMyApiErrors(errors));
56          }
57        );
58      }}
59      render={({
60        values,
61        errors,
62        touched,
63        handleChange,
64        handleBlur,
65        handleSubmit,
66        isSubmitting,
67      }) => (
68        <form onSubmit={handleSubmit}>
69          <input
70            type="email"
71            name="email"
72            onChange={handleChange}
73            onBlur={handleBlur}
74            value={values.email}
75          />
76          {touched.email && errors.email && <div>{errors.email}</div>}
77          <input
78            type="password"
79            name="password"
80            onChange={handleChange}
81            onBlur={handleBlur}
82            value={values.password}
83          />
84          {touched.password && errors.password && <div>{errors.password}</div>}
85          <button type="submit" disabled={isSubmitting}>
86            Submit
87          </button>
88        </form>
89      )}
90    />
91  </div>
92);
93
94export default Basic;