Repository: jaredpalmer/formik
Pull request #183 (2017-09-27 11:09:19)

Add render props to <Field />
This PR allows the usage pattern described in #182 

jaredpalmer: Is there really a need for this though? Just pass props if you need to write this inline.
julienvincent: Passing props as apposed to using the context api adds a significant amount of ceremony, especially in complex forms spread across multiple nested components.

Using  the `<Field />` component api is very elegant, but unfortunately it does not conform to the normal React `onChange` + `value` props pattern. This means that integration with existing custom components is not as simple as just passing them to the `component` prop as they won't be compatible.

#### tl;dr
Adding support for inline lambdas will make compatibility with various custom components much simpler and will allow smoother and easier migration to Formik. Less tears :)
jaredpalmer: By passing props i meant something like this. (this is the way it worked before context 0.9) 

```js
<Formik
   render={props => 
    <form onSubmit={props.handleSubmit}>
      <input 
         name="email"
         type="email"
         onChange={props.handleChange} 
         onBlur={props.handleBlur} 
         value={values.email} 
       />
    </form>}
/>

```
julienvincent: Yea I'm with you on that. My use case is one in which my form input components are sitting in several nested components (complex capture forms) and so those Formik props would need to travel down through two or perhaps three container components before arriving at their respective input component.

Using the context api cleans this up significantly (at the cost perhaps of obscuring links between data and capture).

Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 7ff78a1..ff45b77 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -101,6 +101,16 @@
         "bug",
         "code"
       ]
+    },
+    {
+      "login": "slightlytyler",
+      "name": "Tyler Martinez",
+      "avatar_url": "https://avatars0.githubusercontent.com/u/6819171?v=4",
+      "profile": "http://slightlytyler.com",
+      "contributions": [
+        "bug",
+        "doc"
+      ]
     }
   ]
 }
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..b9557e8
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,10 @@
+# Contributing to Formik
+
+1. Fork this repository to your own GitHub account and then clone it to your local device.
+2. Install the dependencies: `yarn install`
+3. Run `yarn link` to link the local repo to NPM
+4. Run `yarn start` to build and watch for code changes
+5. Run `yarn test` to start Jest
+7. Then npm link this repo inside any other project on your local dev with `yarn link formik`
+8. Then you can use your local version of Formik within your project
+
diff --git a/README.md b/README.md
index 687b43d..6399918 100644
--- a/README.md
+++ b/README.md
@@ -20,14 +20,15 @@ By colocating all of the above in one place, Formik will keep things organized--
 
 I wrote Formik while building a large internal administrative dashboard with [Ian White](https://github.com/eonwhite). With around ~30 unique forms, it quickly became obvious that we could benefit by standardizing not just our input components but also the way in which data flowed through our forms.
 
+### Why not Redux-Form?
+
 By now, you might be thinking, "Why didn't you just use [Redux-Form](https://github.com/erikras/redux-form)?" Good question.
 
- 1. According to our prophet Dan Abramov, [**form state is inherently emphemeral and local**, so tracking it in Redux is  unecessary](https://github.com/reactjs/redux/issues/1287#issuecomment-175351978)
- 2. Redux-Form calls your entire top-level reducer multiple times ON EVERY KEYSTROKE. This is fine for small apps, but as your Redux app grows, input latency will continue increase if you use Redux-Form
- 3. I no longer use [Redux](https://github.com/reactjs/redux) or [MobX](https://mobx.js.org/), just React's setState.
- 4. Redux-Form is 22.5 kB minified gzipped (Formik is 8.9 kB)
+ 1. According to our prophet Dan Abramov, [**form state is inherently emphemeral and local**, so tracking it in Redux (or any kind of Flux library) is unnecessary](https://github.com/reactjs/redux/issues/1287#issuecomment-175351978)
+ 2. Redux-Form calls your entire top-level Redux reducer multiple times ON EVERY SINGLE KEYSTROKE. This is fine for small apps, but as your Redux app grows, input latency will continue increase if you use Redux-Form. 
+ 3. Redux-Form is 22.5 kB minified gzipped (Formik is 9.2 kB)  
 
-My goal with Formik was to create a scalable, performant, form helper with a minimal API that does the really really annoying stuff, and leaves the rest up to you.
+**My goal with Formik was to create a scalable, performant, form helper with a minimal API that does the really really annoying stuff, and leaves the rest up to you.**
 
 ## Influences
 
@@ -56,6 +57,11 @@ You can also try before you buy with this **[demo of Formik on CodeSandbox.io](h
 
 - [An Introduction to Formik](https://youtu.be/-tDy7ds0dag?t=33s) by [Jared Palmer](https://twitter.com/jaredpalmer) @ Spotify NYC. August 15th, 2017.
 
+## Community Articles / Tutorials
+
+- [The Joy of Forms with React and Formik](https://keyholesoftware.com/2017/10/23/the-joy-of-forms-with-react-and-formik/)
+- [Painless React Forms with Formik](https://hackernoon.com/painless-react-forms-with-formik-e61b70473c60)
+
 ## The gist
 
 Formik keeps track of your form's state and then exposes it plus a few reusable methods and event handlers (`handleChange`, `handleBlur`, and `handleSubmit`) to your form via `props`. `handleChange` and `handleBlur` work exactly  as expected--they use a `name` or `id` attribute to figure out which field to update.
@@ -73,12 +79,13 @@ import React from 'react'
 import { withFormik } from 'formik'
 
 // Our inner form component which receives our form's state and updater methods as props
-const InnerForm = ({ values, errors, touched, handleChange, handleSubmit, isSubmitting }) =>
+const InnerForm = ({ 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>}
@@ -86,6 +93,7 @@ const InnerForm = ({ values, errors, touched, handleChange, handleSubmit, isSubm
       type="password"
       name="password"
       onChange={handleChange}
+      onBlur={handleBlur}
       value={values.password}
     />
     {touched.password && errors.password && <div>{errors.password}</div>}
@@ -186,12 +194,13 @@ const Basic = () =>
             }
           )
       }}
-      render={({ values, errors, touched, handleChange, handleSubmit, isSubmitting }) =>
+      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>}
@@ -199,6 +208,7 @@ const Basic = () =>
             type="password"
             name="password"
             onChange={handleChange}
+            onBlur={handleBlur}
             value={values.password}
           />
           {touched.password && errors.password && <div>{errors.password}</div>}
@@ -252,35 +262,33 @@ npm install yup --save
     - [`component`](#component)
     - [`render: (props: FormikProps<Values>) => ReactNode`](#render-props-formikpropsvalues--reactnode)
     - [`children: func`](#children-func)
-    - [`onSubmit: (values: Values, formikBag: FormikBag) => void`](#onsubmit-values-values-formikbag-formikbag--void)
+    - [`enableReinitialize?: boolean`](#enablereinitialize-boolean)
     - [`isInitialValid?: boolean`](#isinitialvalid-boolean)
     - [`initialValues?: Values`](#initialvalues-values)
-    - [`validate?: (values: Values, props: Props) => FormikError<Values> | Promise<any>`](#validate-values-values-props-props--formikerrorvalues--promiseany)
+    - [`onSubmit: (values: Values, formikBag: FormikBag) => void`](#onsubmit-values-values-formikbag-formikbag--void)
+    - [`validate?: (values: Values) => FormikError<Values> | Promise<any>`](#validate-values-values--formikerrorvalues--promiseany)
     - [`validateOnBlur?: boolean`](#validateonblur-boolean)
     - [`validateOnChange?: boolean`](#validateonchange-boolean)
-    - [`validationSchema?: Schema | ((props: Props) => Schema)`](#validationschema-schema--props-props--schema)
+    - [`validationSchema?: Schema | (() => Schema)`](#validationschema-schema----schema)
   - [`<Field />`](#field-)
   - [`<Form />`](#form-)
   - [`withFormik(options)`](#withformikoptions)
     - [`options`](#options)
       - [`displayName?: string`](#displayname-string)
+      - [`enableReinitialize?: boolean`](#enablereinitialize-boolean-1)
       - [`handleSubmit: (values: Values, formikBag: FormikBag) => void`](#handlesubmit-values-values-formikbag-formikbag--void)
         - [The "FormikBag":](#the-formikbag)
       - [`isInitialValid?: boolean | (props: Props) => boolean`](#isinitialvalid-boolean--props-props--boolean)
       - [`mapPropsToValues?: (props: Props) => Values`](#mappropstovalues-props-props--values)
-      - [`validate?: (values: Values, props: Props) => FormikError<Values> | Promise<any>`](#validate-values-values-props-props--formikerrorvalues--promiseany-1)
+      - [`validate?: (values: Values, props: Props) => FormikError<Values> | Promise<any>`](#validate-values-values-props-props--formikerrorvalues--promiseany)
       - [`validateOnBlur?: boolean`](#validateonblur-boolean-1)
       - [`validateOnChange?: boolean`](#validateonchange-boolean-1)
-      - [`validationSchema?: Schema | ((props: Props) => Schema)`](#validationschema-schema--props-props--schema-1)
+      - [`validationSchema?: Schema | ((props: Props) => Schema)`](#validationschema-schema--props-props--schema)
     - [Injected props and methods](#injected-props-and-methods)
 - [Guides](#guides)
   - [React Native](#react-native)
     - [Why use `setFieldValue` instead of `handleChange`?](#why-use-setfieldvalue-instead-of-handlechange)
-    - [Avoiding a Render Callback](#avoiding-a-render-callback)
-  - [Testing Formik](#testing-formik)
-    - [Dummy Form](#dummy-form)
-    - [Simulating input](#simulating-input)
-    - [Simulating form submission](#simulating-form-submission)
+    - [Avoiding new functions in render](#avoiding-new-functions-in-render)
 - [Organizations and projects using Formik](#organizations-and-projects-using-formik)
 - [Authors](#authors)
 - [Contributors](#contributors)
@@ -341,6 +349,7 @@ const EditUserDialog = ({ user, updateUser, onClose }) => {
               type="email"
               name="email"
               onChange={handleChange}
+              onBlur={handleBlur}
               value={values.email}
             />
             {errors.email &&
@@ -352,6 +361,7 @@ const EditUserDialog = ({ user, updateUser, onClose }) => {
               type="text"
               name="facebook"
               onChange={handleChange}
+              onBlur={handleBlur}
               value={values.facebook}
             />
             {errors.facebook &&
@@ -363,6 +373,7 @@ const EditUserDialog = ({ user, updateUser, onClose }) => {
               type="text"
               name="twitter"
               onChange={handleChange}
+              onBlur={handleBlur}
               value={values.twitter}
             />
             {errors.twitter &&
@@ -646,11 +657,9 @@ const ContactForm = ({ handleSubmit, handleChange, handleBlur, values, errors })
 ```
 
 
+#### `enableReinitialize?: boolean`
 
-#### `onSubmit: (values: Values, formikBag: FormikBag) => void`
-Your form submission handler. It is passed your forms [`values`] and the "FormikBag", which includes an object containing a subset of the [injected props and methods](/#injected-props-and-methods) (i.e. all the methods with names that start with `set<Thing>` + `resetForm`) and any props that were passed to the the wrapped component.
-
-Note: [`errors`], [`touched`], [`status`] and all event handlers are NOT included in the `FormikBag`.
+Default is `false`. Control whether Formik should reset the form if [`initialValues`] changes (using deep equality).
 
 #### `isInitialValid?: boolean`
 
@@ -658,11 +667,18 @@ Default is `false`. Control the initial value of [`isValid`] prop prior to mount
 
 #### `initialValues?: Values`
 
-If this option is specified, then Formik will transfer its results into updatable form state and make these values available to the new component as [`props.values`][`values`]. If `mapPropsToValues` is not specified, then Formik will map all props that are not functions to the inner component's [`props.values`][`values`]. That is, if you omit it, Formik will only pass `props` where `typeof props[k] !== 'function'`, where `k` is some key.
+Initial field values of the form, Formik will make these values available to render methods component as [`props.values`][`values`]. 
 
-Even if your form is not receiving any props from its parent, use `mapPropsToValues` to initialize your forms empty state.
+Even if your form is empty by default, you must initialize all fields with initial values otherwise React will throw an error saying that you have changed an input from uncontrolled to controlled.
+
+Note: `initialValues` not available to the higher-order component, use [`mapPropsToValues`] instead.
+
+#### `onSubmit: (values: Values, formikBag: FormikBag) => void`
+Your form submission handler. It is passed your forms [`values`] and the "FormikBag", which includes an object containing a subset of the [injected props and methods](#injected-props-and-methods) (i.e. all the methods with names that start with `set<Thing>` + `resetForm`) and any props that were passed to the the wrapped component.
 
-#### `validate?: (values: Values, props: Props) => FormikError<Values> | Promise<any>`
+Note: [`errors`], [`touched`], [`status`] and all event handlers are NOT included in the `FormikBag`.
+
+#### `validate?: (values: Values) => FormikError<Values> | Promise<any>`
 
 _Note: I suggest using [`validationSchema`] and Yup for validation. However, `validate` is a dependency-free, straightforward way to validate your forms._
 
@@ -714,7 +730,7 @@ Default is `true`. Use this option to run validations on `blur` events. More spe
 
 Default is `true`. Use this option to tell Formik to run validations on `change` events and `change`-related methods. More specifically, when either [`handleChange`], [`setFieldValue`], or [`setValues`] are called.
 
-#### `validationSchema?: Schema | ((props: Props) => Schema)`
+#### `validationSchema?: Schema | (() => Schema)`
 
 [A Yup schema](https://github.com/jquense/yup) or a function that returns a Yup schema. This is used for validation. Errors are mapped by key to the inner component's [`errors`]. Its keys should match those of [`values`].
 
@@ -754,7 +770,7 @@ const Example = () => (
 
 const CustomInputComponent: React.SFC<FormikProps<Values> & CustomInputProps> => ({
   field, // { name, value, onChange, onBlur }
-  form: { touched, errors } // also values, setXXXX, handleXXXX, isDirty, isValid, status, etc.
+  form: { touched, errors } // also values, setXXXX, handleXXXX, dirty, isValid, status, etc.
   ...props
 }) => (
   <div>
@@ -815,8 +831,12 @@ Create a higher-order React component class that passes props and form handlers
 ##### `displayName?: string`
 When your inner form component is a stateless functional component, you can use the `displayName` option to give the component a proper name so you can more easily find it in [React DevTools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en). If specified, your wrapped form will show up as `Formik(displayName)`. If omitted, it will show up as `Formik(Component)`. This option is not required for class components (e.g. `class XXXXX extends React.Component {..}`).
 
+##### `enableReinitialize?: boolean`
+
+Default is `false`. Control whether Formik should reset the form if the wrapped component props change (using deep equality).
+
 ##### `handleSubmit: (values: Values, formikBag: FormikBag) => void`
-Your form submission handler. It is passed your forms [`values`] and the "FormikBag", which includes an object containing a subset of the [injected props and methods](/#injected-props-and-methods) (i.e. all the methods with names that start with `set<Thing>` + `resetForm`) and any props that were passed to the the wrapped component.
+Your form submission handler. It is passed your forms [`values`] and the "FormikBag", which includes an object containing a subset of the [injected props and methods](#injected-props-and-methods) (i.e. all the methods with names that start with `set<Thing>` + `resetForm`) and any props that were passed to the the wrapped component.
 
 ###### The "FormikBag":
 
@@ -845,7 +865,7 @@ Even if your form is not receiving any props from its parent, use `mapPropsToVal
 
 ##### `validate?: (values: Values, props: Props) => FormikError<Values> | Promise<any>`
 
-_Note: I suggest using [`validateSchema`] and Yup for validation. However, `validate` is a dependency-free, straightforward way to validate your forms._
+_Note: I suggest using [`validationSchema`] and Yup for validation. However, `validate` is a dependency-free, straightforward way to validate your forms._
 
 Validate the form's [`values`] with function. This function can either be:
 
@@ -1001,9 +1021,9 @@ export const MyReactNativeForm = props =>
 // ...
 ```
 
-#### Avoiding a Render Callback
+#### Avoiding new functions in render
 
-If you are like me and do not like render callbacks, I suggest treating React Native's `<TextInput/>` as if it were another 3rd party custom input element:
+If for a any reason you wish to avoid creating new functions on each render, I suggest treating React Native's `<TextInput/>` as if it were another 3rd party custom input element:
 
   - Write your own class wrapper around the custom input element
   - Pass the custom component [`props.setFieldValue`][`setFieldValue`] instead of [`props.handleChange`][`handleChange`]
@@ -1069,182 +1089,6 @@ const MyReactNativeForm = props => (
 export default MyReactNativeForm
 ```
 
-### Testing Formik
-
-_This section is a work in progress._
-
-The suggested approach to testing Formik forms is with Airbnb's [Enzyme](https://github.com/airbnb/enzyme) test utility library.
-
-The documentation and examples in this guide use Facebook's [Jest](https://facebook.github.io/jest) test runner. However, feel free to use [mocha](https://mochajs.org/) and [chai](http://chaijs.com/) if you prefer that.
-
-To get started with Enzyme, you can simply install it with npm:
-
-```bash
-npm i  enzyme --save-dev
-```
-
-If you are using React >=15.5, in addition to enzyme, you will have to ensure that you also have the following npm modules installed if they were not already:
-
-```bash
-npm i react-test-renderer react-dom  --save-dev
-```
-
-####  Dummy Form
-Imagine we have a basic form with one field `name`.
-
-```js
-// MyForm.js
-import { Formik } from 'formik';
-import Yup from 'yup';
-
-export const validationSchema = Yup.object().shape({
-  name: Yup.string()
-    .min(2, 'Must be longer than 2 characters')
-    .max(30, "No one's name is that long")
-    .required('Required'),
-});
-
-export const handleSubmit = (values, { setSubmitting }) => {
-  setTimeout(() => {
-    setSubmitting(false);
-  }, 1000);
-};
-
-export const mapPropsToValues = props => ({ name: '' });
-
-export const MyFormInner = ({
-  values,
-  handleSubmit,
-  handleChange,
-  handleBlur,
-  setStatus,
-  status,
-  errors,
-  isSubmitting,
-}) => {
-  return (
-    <form onSubmit={handleSubmit}>
-      <input
-        type="text"
-        onChange={handleChange}
-        onBlur={handleBlur}
-        value={values.name}
-        name="name"
-      />
-      {errors.name &&
-        <div id="feedback">
-          {errors.name}
-        </div>}
-      {isSubmitting && <div id="submitting">Submitting</div>}
-      {status &&
-        !!status.myStatusMessage &&
-        <div id="status">
-          {status.myStatusMessage}
-        </div>}
-      <button type="submit">Submit</button>
-    </form>
-  );
-};
-
-export default Formik({
-  mapPropsToValues,
-  validationSchema,
-  handleSubmit,
-})(MyFormInner);
-```
-
-#### Simulating input
-
-We can test that our UI is updating properly by using Enzyme's `shallow` renderer in addition to its `dive()` and `simulate()` methods. This lets us render the Formik-enhanced form, but then jump down and run simulations and assertions from the perspective of your inner form.
-
-```js
-// MyForm.test.js
-import MyForm, { MyInnerForm } from './MyForm';
-
-describe('MyForm', () => {
-  test('should update an input when it is changed', () => {
-    const tree = shallow(<MyForm />);
-
-    tree.find(MyInnerForm).dive().find('input').simulate('change', {
-      // you must add this next line as (Formik calls e.persist() internally)
-      persist: () => {},
-      // simulate changing e.target.name and e.target.value
-      target: {
-        name: 'name',
-        value: 'ian',
-      },
-    });
-
-    const newValue = tree.find(MyInnerForm).dive().find('input').props().value;
-
-    expect(newValue).toEqual('ian');
-  });
-});
-
-```
-
-#### Simulating form submission
-
-```js
-// MyForm.test.js
-import MyForm, { MyInnerForm, validationSchema } from './MyForm';
-
-describe('MyForm', () => {
-  test('submits the form', () => {
-    const tree = shallow(<MyForm />);
-    expect(tree.find(MyInnerForm).dive().find('#submitting')).toHaveLength(0);
-
-    // simulate submit event. this is always sync! async calls to setState are swallowed.
-    // be careful of false positives
-    tree.find(MyInnerForm).dive().find('form').simulate('submit', {
-      preventDefault: () => {}, // no op
-    });
-
-    // Because the simulated event is 100% sync, we can use it to test the synchronous changes
-    // here. Any async stuff you do inside handleSubmit will be swallowed. Thus our UI
-    // will see the following changes:
-    // - isSubmitting -> true (even if you set it to false asynchronously in your handleSubmit)
-    // - touched: all fields
-    expect(tree.find(Form).dive().find('#submitting')).toHaveLength(1);
-    expect(
-      tree.find(Form).dive().find('button[type="submit"]').props().disabled
-    ).toBe(true);
-  });
-
-  test('what happens when the form is submitted', async () => {
-    const tree = shallow(<MyForm />);
-
-    expect(tree.find(MyInnerForm).dive().find('#submitting')).toHaveLength(0);
-
-    await mockCallsToMyApi();
-    await tree.find(MyInnerForm).props().submitForm();
-
-    // check that ui has completely updated
-    expect(
-      tree.find(MyInnerForm).update().dive().find('#submitting')
-    ).toHaveLength(0);
-    expect(tree.find(MyInnerForm).update().dive().find('#status').text).toEqual(
-      'Success!'
-    );
-    expect(
-      tree
-        .find(MyInnerForm)
-        .update()
-        .dive()
-        .find('button[type="submit"]')
-        .props().disabled
-    ).toBe(false);
-
-    // check that props have updated
-    expect(tree.find(MyInnerForm).props().status).toEqual({
-      myStatusMessage: 'Success!',
-    });
-    expect(tree.find(MyInnerForm).props().errors).toEqual({});
-    expect(tree.find(MyInnerForm).props().touched).toEqual({ name: true }); // submit will touch all fields
-  });
-});
-```
-
 ## Organizations and projects using Formik
 
 [List of organizations and projects using Formik](https://github.com/jaredpalmer/formik/issues/87)
@@ -1261,7 +1105,7 @@ Formik is made with <3 thanks to these wonderful people ([emoji key](https://git
 <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
 | [<img src="https://avatars2.githubusercontent.com/u/4060187?v=4" width="100px;"/><br /><sub>Jared Palmer</sub>](http://jaredpalmer.com)<br />[💬](#question-jaredpalmer "Answering Questions") [💻](https://github.com/jaredpalmer/formik/commits?author=jaredpalmer "Code") [🎨](#design-jaredpalmer "Design") [📖](https://github.com/jaredpalmer/formik/commits?author=jaredpalmer "Documentation") [💡](#example-jaredpalmer "Examples") [🤔](#ideas-jaredpalmer "Ideas, Planning, & Feedback") [👀](#review-jaredpalmer "Reviewed Pull Requests") [⚠️](https://github.com/jaredpalmer/formik/commits?author=jaredpalmer "Tests") | [<img src="https://avatars0.githubusercontent.com/u/109324?v=4" width="100px;"/><br /><sub>Ian White</sub>](https://www.stardog.io)<br />[💬](#question-eonwhite "Answering Questions") [🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Aeonwhite "Bug reports") [💻](https://github.com/jaredpalmer/formik/commits?author=eonwhite "Code") [📖](https://github.com/jaredpalmer/formik/commits?author=eonwhite "Documentation") [🤔](#ideas-eonwhite "Ideas, Planning, & Feedback") [👀](#review-eonwhite "Reviewed Pull Requests") | [<img src="https://avatars0.githubusercontent.com/u/829963?v=4" width="100px;"/><br /><sub>Andrej Badin</sub>](http://andrejbadin.com)<br />[💬](#question-Andreyco "Answering Questions") [🐛](https://github.com/jaredpalmer/formik/issues?q=author%3AAndreyco "Bug reports") [📖](https://github.com/jaredpalmer/formik/commits?author=Andreyco "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/91115?v=4" width="100px;"/><br /><sub>Adam Howard</sub>](http://adz.co.de)<br />[💬](#question-skattyadz "Answering Questions") [🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Askattyadz "Bug reports") [🤔](#ideas-skattyadz "Ideas, Planning, & Feedback") [👀](#review-skattyadz "Reviewed Pull Requests") | [<img src="https://avatars1.githubusercontent.com/u/6711845?v=4" width="100px;"/><br /><sub>Vlad Shcherbin</sub>](https://github.com/VladShcherbin)<br />[💬](#question-VladShcherbin "Answering Questions") [🐛](https://github.com/jaredpalmer/formik/issues?q=author%3AVladShcherbin "Bug reports") [🤔](#ideas-VladShcherbin "Ideas, Planning, & Feedback") | [<img src="https://avatars3.githubusercontent.com/u/383212?v=4" width="100px;"/><br /><sub>Brikou CARRE</sub>](https://github.com/brikou)<br />[🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Abrikou "Bug reports") [📖](https://github.com/jaredpalmer/formik/commits?author=brikou "Documentation") | [<img src="https://avatars0.githubusercontent.com/u/5314713?v=4" width="100px;"/><br /><sub>Sam Kvale</sub>](http://skvale.github.io)<br />[🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Askvale "Bug reports") [💻](https://github.com/jaredpalmer/formik/commits?author=skvale "Code") [⚠️](https://github.com/jaredpalmer/formik/commits?author=skvale "Tests") |
 | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
-| [<img src="https://avatars0.githubusercontent.com/u/13765558?v=4" width="100px;"/><br /><sub>Jon Tansey</sub>](http://jon.tansey.info)<br />[🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Ajontansey "Bug reports") [💻](https://github.com/jaredpalmer/formik/commits?author=jontansey "Code") |
+| [<img src="https://avatars0.githubusercontent.com/u/13765558?v=4" width="100px;"/><br /><sub>Jon Tansey</sub>](http://jon.tansey.info)<br />[🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Ajontansey "Bug reports") [💻](https://github.com/jaredpalmer/formik/commits?author=jontansey "Code") | [<img src="https://avatars0.githubusercontent.com/u/6819171?v=4" width="100px;"/><br /><sub>Tyler Martinez</sub>](http://slightlytyler.com)<br />[🐛](https://github.com/jaredpalmer/formik/issues?q=author%3Aslightlytyler "Bug reports") [📖](https://github.com/jaredpalmer/formik/commits?author=slightlytyler "Documentation") |
 <!-- ALL-CONTRIBUTORS-LIST:END -->
 
 This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
diff --git a/package.json b/package.json
index 7835323..1356d66 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "formik",
   "description": "Forms in React, without tears",
-  "version": "0.9.2",
+  "version": "0.9.4",
   "license": "MIT",
   "author": "Jared Palmer <jared@palmer.net>",
   "repository": "jaredpalmer/formik",
@@ -79,11 +79,16 @@
     "yup": "0.21.3"
   },
   "lint-staged": {
-    "*.(ts|tsx)": [
+    "**/*.{ts,tsx}": [
       "prettier --trailing-comma es5 --single-quote --write",
       "git add"
     ]
   },
+  "prettier": {
+    "trailingComma": "es5",
+    "singleQuote": true,
+    "semi": true
+  },
   "jest": {
     "collectCoverageFrom": [
       "src/**/*.{ts,tsx}"
diff --git a/src/Field.tsx b/src/Field.tsx
index 9cc3942..4c1a95f 100644
--- a/src/Field.tsx
+++ b/src/Field.tsx
@@ -8,7 +8,7 @@ import { FormikProps } from './formik';
  * context and wiring up forms.
  */
 export const Field: React.SFC<any> = (
-  { component = 'input', name, ...props },
+  { component = 'input', render, children, name, ...props },
   context
 ) => {
   const field = {
@@ -27,10 +27,17 @@ export const Field: React.SFC<any> = (
           field,
           form: context.formik,
         };
-  return React.createElement(component, {
+  const componentProps = {
     ...props,
     ...bag,
-  });
+  };
+  if (typeof render === 'function') {
+    return render(componentProps);
+  }
+  if (typeof children === 'function') {
+    return children(componentProps);
+  }
+  return React.createElement(component, componentProps);
 };
 
 Field.contextTypes = {
diff --git a/src/formik.tsx b/src/formik.tsx
index 18a5291..2cabced 100644
--- a/src/formik.tsx
+++ b/src/formik.tsx
@@ -51,11 +51,13 @@ export interface FormikState<Values> {
 /**
  * Formik computed properties. These are read-only.
  */
-export interface FormikComputedProps {
+export interface FormikComputedProps<Values> {
   /** True if any input has been touched. False otherwise. */
   readonly dirty: boolean;
   /** Result of isInitiallyValid on mount, then whether true values pass validation. */
   readonly isValid: boolean;
+  /** initialValues */
+  readonly initialValues: Values;
 }
 
 /**
@@ -115,6 +117,8 @@ export interface FormikSharedConfig {
   validateOnBlur?: boolean;
   /** Tell Formik if initial form values are valid or not on first render */
   isInitialValid?: boolean | ((props: object) => boolean | undefined);
+  /** Should Formik reset the form when new initialValues change */
+  enableReinitialize?: boolean;
 }
 
 /**
@@ -165,7 +169,7 @@ export interface FormikConfig extends FormikSharedConfig {
 export type FormikProps<Values> = FormikState<Values> &
   FormikActions<Values> &
   FormikHandlers &
-  FormikComputedProps;
+  FormikComputedProps<Values>;
 
 const isEmptyChildren = (children: any) => React.Children.count(children) === 0;
 
@@ -176,6 +180,7 @@ export class Formik<
     validateOnChange: true,
     validateOnBlur: true,
     isInitialValid: false,
+    enableReinitialize: false,
   };
 
   static propTypes = {
@@ -189,12 +194,15 @@ export class Formik<
     component: PropTypes.func,
     render: PropTypes.func,
     children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
+    enableReinitialize: PropTypes.bool,
   };
 
   static childContextTypes = {
     formik: PropTypes.object,
   };
 
+  initialValues: any;
+
   getChildContext() {
     const dirty =
       values<boolean>(this.state.touched).filter(Boolean).length > 0;
@@ -225,6 +233,7 @@ export class Formik<
         setSubmitting: this.setSubmitting,
         resetForm: this.resetForm,
         submitForm: this.submitForm,
+        initialValues: this.initialValues,
       },
     };
   }
@@ -237,11 +246,17 @@ export class Formik<
       touched: {},
       isSubmitting: false,
     };
+
+    this.initialValues = props.initialValues || ({} as any);
   }
 
   componentWillReceiveProps(nextProps: Props) {
     // If the initialValues change, reset the form
-    if (!isEqual(nextProps.initialValues, this.props.initialValues)) {
+    if (
+      this.props.enableReinitialize &&
+      !isEqual(nextProps.initialValues, this.props.initialValues)
+    ) {
+      this.initialValues = nextProps.initialValues;
       this.resetForm(nextProps.initialValues);
     }
   }
@@ -391,7 +406,7 @@ Formik cannot determine which value to update. For more info see https://github.
       this.runValidations(
         {
           ...this.state.values as object,
-          [field]: value,
+          [field]: val,
         } as Object
       );
     }
@@ -491,16 +506,16 @@ Formik cannot determine which value to update. For more info see https://github.
 
   executeSubmit = () => {
     this.props.onSubmit(this.state.values, {
-      setStatus: this.setStatus,
-      setTouched: this.setTouched,
-      setErrors: this.setErrors,
+      resetForm: this.resetForm,
       setError: this.setError,
-      setValues: this.setValues,
+      setErrors: this.setErrors,
       setFieldError: this.setFieldError,
-      setFieldValue: this.setFieldValue,
       setFieldTouched: this.setFieldTouched,
+      setFieldValue: this.setFieldValue,
+      setStatus: this.setStatus,
       setSubmitting: this.setSubmitting,
-      resetForm: this.resetForm,
+      setTouched: this.setTouched,
+      setValues: this.setValues,
       submitForm: this.submitForm,
     });
   };
@@ -556,6 +571,10 @@ Formik cannot determine which value to update. For more info see https://github.
   };
 
   resetForm = (nextValues?: any) => {
+    if (nextValues) {
+      this.initialValues = nextValues;
+    }
+
     this.setState({
       isSubmitting: false,
       errors: {},
@@ -582,20 +601,21 @@ Formik cannot determine which value to update. For more info see https://github.
         : isInitialValid !== false && isFunction(isInitialValid)
           ? (isInitialValid as (props: Props) => boolean)(this.props)
           : isInitialValid as boolean,
-      handleSubmit: this.handleSubmit,
-      handleChange: this.handleChange,
       handleBlur: this.handleBlur,
+      handleChange: this.handleChange,
       handleReset: this.handleReset,
-      setStatus: this.setStatus,
-      setTouched: this.setTouched,
-      setErrors: this.setErrors,
+      handleSubmit: this.handleSubmit,
+      initialValues: this.initialValues,
+      resetForm: this.resetForm,
       setError: this.setError,
-      setValues: this.setValues,
+      setErrors: this.setErrors,
       setFieldError: this.setFieldError,
-      setFieldValue: this.setFieldValue,
       setFieldTouched: this.setFieldTouched,
+      setFieldValue: this.setFieldValue,
+      setStatus: this.setStatus,
       setSubmitting: this.setSubmitting,
-      resetForm: this.resetForm,
+      setTouched: this.setTouched,
+      setValues: this.setValues,
       submitForm: this.submitForm,
     };
     return component
diff --git a/src/withFormik.tsx b/src/withFormik.tsx
index 1c572bb..c821cfb 100644
--- a/src/withFormik.tsx
+++ b/src/withFormik.tsx
@@ -22,7 +22,7 @@ export type InjectedFormikProps<Props, Values> = Props &
   FormikState<Values> &
   FormikActions<Values> &
   FormikHandlers &
-  FormikComputedProps;
+  FormikComputedProps<Values>;
 
 /**
  * Formik actions + { props }


Test patch:
diff --git a/test/formik.test.tsx b/test/formik.test.tsx
index b07d1a5..1fdd265 100644
--- a/test/formik.test.tsx
+++ b/test/formik.test.tsx
@@ -659,16 +659,21 @@ describe('Formik Next', () => {
   });
 
   describe('componentWillReceiveProps', () => {
-    let form, initialValues;
+    let form, defaultForm, initialValues;
     beforeEach(() => {
       initialValues = {
         name: 'formik',
         github: { repoUrl: 'https://github.com/jaredpalmer/formik' },
         watchers: ['ian', 'sam'],
       };
-      form = new Formik({ initialValues, onSubmit: jest.fn() });
+      form = new Formik({
+        initialValues,
+        onSubmit: jest.fn(),
+        enableReinitialize: true,
+      });
       form.resetForm = jest.fn();
     });
+
     it('should not resetForm if new initialValues are the same as previous', () => {
       const newInitialValues = Object.assign({}, initialValues);
       form.componentWillReceiveProps({
@@ -679,9 +684,10 @@ describe('Formik Next', () => {
     });
 
     it('should resetForm if new initialValues are different than previous', () => {
-      const newInitialValues = Object.assign({}, initialValues, {
+      const newInitialValues = {
+        ...initialValues,
         watchers: ['jared', 'ian', 'sam'],
-      });
+      };
       form.componentWillReceiveProps({
         initialValues: newInitialValues,
         onSubmit: jest.fn(),
@@ -690,14 +696,32 @@ describe('Formik Next', () => {
     });
 
     it('should resetForm if new initialValues are deeply different than previous', () => {
-      const newInitialValues = Object.assign({}, initialValues, {
+      const newInitialValues = {
+        ...initialValues,
         github: { repoUrl: 'different' },
-      });
+      };
       form.componentWillReceiveProps({
         initialValues: newInitialValues,
         onSubmit: jest.fn(),
       });
       expect(form.resetForm).toHaveBeenCalled();
     });
+
+    it('should NOT resetForm without enableReinitialize flag', () => {
+      form = new Formik({
+        initialValues,
+        onSubmit: jest.fn(),
+      });
+      form.resetForm = jest.fn();
+      const newInitialValues = {
+        ...initialValues,
+        watchers: ['jared', 'ian', 'sam'],
+      };
+      form.componentWillReceiveProps({
+        initialValues: newInitialValues,
+        onSubmit: jest.fn(),
+      });
+      expect(form.resetForm).not.toHaveBeenCalled();
+    });
   });
 });