Repository: final-form/react-final-form
Pull request #145 (2018-02-07 14:25:31)

Add isEqual prop to typescript definition

codecov[bot]: # [Codecov](https://codecov.io/gh/final-form/react-final-form/pull/145?src=pr&el=h1) Report
> Merging [#145](https://codecov.io/gh/final-form/react-final-form/pull/145?src=pr&el=desc) into [master](https://codecov.io/gh/final-form/react-final-form/commit/ac4f535298f1233feb66ff93f10f5a2cc4dd6cc0?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/final-form/react-final-form/pull/145/graphs/tree.svg?token=s8VUe6IxMZ&src=pr&width=650&height=150)](https://codecov.io/gh/final-form/react-final-form/pull/145?src=pr&el=tree)

```diff
@@          Coverage Diff          @@
##           master   #145   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files          10     10           
  Lines         169    169           
  Branches       54     54           
=====================================
  Hits          169    169
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/final-form/react-final-form/pull/145?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/final-form/react-final-form/pull/145?src=pr&el=footer). Last update [ac4f535...bc7ee4c](https://codecov.io/gh/final-form/react-final-form/pull/145?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/README.md b/README.md
index ead2279..6e029ce 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 ![React Final Form](banner.png)
 
-[![NPM Version](https://img.shields.io/npm/v/react-final-form.svg?style=flat)](https://www.npmjs.com/package/react-final-form)
+[![Backers on Open Collective](https://opencollective.com/final-form/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/final-form/sponsors/badge.svg)](#sponsors) [![NPM Version](https://img.shields.io/npm/v/react-final-form.svg?style=flat)](https://www.npmjs.com/package/react-final-form)
 [![NPM Downloads](https://img.shields.io/npm/dm/react-final-form.svg?style=flat)](https://www.npmjs.com/package/react-final-form)
 [![Build Status](https://travis-ci.org/final-form/react-final-form.svg?branch=master)](https://travis-ci.org/final-form/react-final-form)
 [![codecov.io](https://codecov.io/gh/final-form/react-final-form/branch/master/graph/badge.svg)](https://codecov.io/gh/final-form/react-final-form)
@@ -706,3 +706,29 @@ A function that initializes the form values.
 
 A function that resets the form values to their last initialized values.
 [See the 🏁 Final Form docs on `reset`](https://github.com/final-form/final-form#reset---void).
+
+## Contributors
+
+This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
+<a href="graphs/contributors"><img src="https://opencollective.com/final-form/contributors.svg?width=890" /></a>
+
+## Backers
+
+Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/final-form#backer)]
+
+<a href="https://opencollective.com/final-form#backers" target="_blank"><img src="https://opencollective.com/final-form/backers.svg?width=890"></a>
+
+## Sponsors
+
+Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/final-form#sponsor)]
+
+<a href="https://opencollective.com/final-form/sponsor/0/website" target="_blank"><img src="https://opencollective.com/final-form/sponsor/0/avatar.svg"></a>
+<a href="https://opencollective.com/final-form/sponsor/1/website" target="_blank"><img src="https://opencollective.com/final-form/sponsor/1/avatar.svg"></a>
+<a href="https://opencollective.com/final-form/sponsor/2/website" target="_blank"><img src="https://opencollective.com/final-form/sponsor/2/avatar.svg"></a>
+<a href="https://opencollective.com/final-form/sponsor/3/website" target="_blank"><img src="https://opencollective.com/final-form/sponsor/3/avatar.svg"></a>
+<a href="https://opencollective.com/final-form/sponsor/4/website" target="_blank"><img src="https://opencollective.com/final-form/sponsor/4/avatar.svg"></a>
+<a href="https://opencollective.com/final-form/sponsor/5/website" target="_blank"><img src="https://opencollective.com/final-form/sponsor/5/avatar.svg"></a>
+<a href="https://opencollective.com/final-form/sponsor/6/website" target="_blank"><img src="https://opencollective.com/final-form/sponsor/6/avatar.svg"></a>
+<a href="https://opencollective.com/final-form/sponsor/7/website" target="_blank"><img src="https://opencollective.com/final-form/sponsor/7/avatar.svg"></a>
+<a href="https://opencollective.com/final-form/sponsor/8/website" target="_blank"><img src="https://opencollective.com/final-form/sponsor/8/avatar.svg"></a>
+<a href="https://opencollective.com/final-form/sponsor/9/website" target="_blank"><img src="https://opencollective.com/final-form/sponsor/9/avatar.svg"></a>
diff --git a/package.json b/package.json
index 795ffda..1931006 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,8 @@
   "scripts": {
     "start": "nps",
     "test": "nps test",
-    "precommit": "lint-staged && npm start validate"
+    "precommit": "lint-staged && npm start validate",
+    "postinstall": "opencollective postinstall"
   },
   "author":
     "Erik Rasmussen <rasmussenerik@gmail.com> (http://github.com/erikras)",
@@ -49,6 +50,7 @@
     "lint-staged": "^6.0.1",
     "nps": "^5.7.1",
     "nps-utils": "^1.5.0",
+    "opencollective": "^1.0.3",
     "prettier": "^1.8.2",
     "prettier-eslint-cli": "^4.4.2",
     "prop-types": "^15.6.0",
@@ -89,5 +91,9 @@
       "path": "dist/react-final-form.cjs.js",
       "threshold": "3kB"
     }
-  ]
+  ],
+  "collective": {
+    "type": "opencollective",
+    "url": "https://opencollective.com/final-form"
+  }
 }
diff --git a/src/Field.js b/src/Field.js
index 714546d..6b34dfa 100644
--- a/src/Field.js
+++ b/src/Field.js
@@ -19,7 +19,7 @@ type State = {
   state: FieldState
 }
 
-export default class Field extends React.PureComponent<Props, State> {
+export default class Field extends React.Component<Props, State> {
   context: ReactContext
   props: Props
   state: State
diff --git a/src/FormSpy.js b/src/FormSpy.js
index 9654a4b..4a7ad01 100644
--- a/src/FormSpy.js
+++ b/src/FormSpy.js
@@ -11,7 +11,7 @@ import { all } from './ReactFinalForm'
 
 type State = { state: FormState }
 
-export default class FormSpy extends React.PureComponent<Props, State> {
+export default class FormSpy extends React.Component<Props, State> {
   context: ReactContext
   props: Props
   state: State
diff --git a/src/ReactFinalForm.js b/src/ReactFinalForm.js
index be1aae0..f0d5553 100644
--- a/src/ReactFinalForm.js
+++ b/src/ReactFinalForm.js
@@ -36,7 +36,7 @@ type State = {
   state: FormState
 }
 
-export default class ReactFinalForm extends React.PureComponent<Props, State> {
+export default class ReactFinalForm extends React.Component<Props, State> {
   context: ReactContext
   props: Props
   state: State
diff --git a/src/index.d.ts b/src/index.d.ts
index e3b7a3d..f68b3f0 100644
--- a/src/index.d.ts
+++ b/src/index.d.ts
@@ -71,6 +71,7 @@ export interface FieldProps extends RenderableProps<FieldRenderProps> {
   format?: ((value: any, name: string) => any) | null
   parse?: ((value: any, name: string) => any) | null
   name: string
+  isEqual?: (a: any, b: any) => boolean
   subscription?: FieldSubscription
   validate?: (value: any, allValues: object) => any
   value?: any


Test patch:
diff --git a/src/Field.test.js b/src/Field.test.js
index 449f247..424ee47 100644
--- a/src/Field.test.js
+++ b/src/Field.test.js
@@ -39,14 +39,14 @@ describe('Field', () => {
     expect(renderInput).not.toHaveBeenCalled()
     const dom = TestUtils.renderIntoDocument(<Container />)
     expect(renderInput).toHaveBeenCalled()
-    expect(renderInput).toHaveBeenCalledTimes(1)
-    expect(renderInput.mock.calls[0][0].input.value).toBe('Odie')
+    expect(renderInput).toHaveBeenCalledTimes(2)
+    expect(renderInput.mock.calls[1][0].input.value).toBe('Odie')
 
     const button = TestUtils.findRenderedDOMComponentWithTag(dom, 'button')
     TestUtils.Simulate.click(button)
 
-    expect(renderInput).toHaveBeenCalledTimes(2)
-    expect(renderInput.mock.calls[1][0].input.value).toBe('Garfield')
+    expect(renderInput).toHaveBeenCalledTimes(4)
+    expect(renderInput.mock.calls[3][0].input.value).toBe('Garfield')
   })
 
   it('should not resubscribe if name changes when not inside a <Form> (duh)', () => {
@@ -97,7 +97,7 @@ describe('Field', () => {
     // called twice due to field registration adding touched and visited values
     expect(render).toHaveBeenCalledTimes(2)
     expect(renderInput).toHaveBeenCalled()
-    expect(renderInput).toHaveBeenCalledTimes(1)
+    expect(renderInput).toHaveBeenCalledTimes(2)
   })
 
   it('should unsubscribe on unmount', () => {
@@ -245,20 +245,20 @@ describe('Field', () => {
     expect(render.mock.calls[1][0].values.foo).toBeUndefined()
 
     expect(format).toHaveBeenCalled()
-    expect(format).toHaveBeenCalledTimes(1)
+    expect(format).toHaveBeenCalledTimes(2)
     expect(format.mock.calls[0]).toEqual([undefined, 'foo'])
 
     expect(renderInput).toHaveBeenCalled()
-    expect(renderInput).toHaveBeenCalledTimes(1)
+    expect(renderInput).toHaveBeenCalledTimes(2)
     expect(renderInput.mock.calls[0][0].input.value).toBe('format.undefined')
 
     renderInput.mock.calls[0][0].input.onChange('bar')
 
-    expect(format).toHaveBeenCalledTimes(2)
-    expect(format.mock.calls[1]).toEqual(['bar', 'foo'])
+    expect(format).toHaveBeenCalledTimes(4)
+    expect(format.mock.calls[3]).toEqual(['bar', 'foo'])
 
-    expect(renderInput).toHaveBeenCalledTimes(2)
-    expect(renderInput.mock.calls[1][0].input.value).toBe('format.bar')
+    expect(renderInput).toHaveBeenCalledTimes(4)
+    expect(renderInput.mock.calls[3][0].input.value).toBe('format.bar')
   })
 
   it('should accept a null format prop to preserve undefined values', () => {
@@ -281,13 +281,13 @@ describe('Field', () => {
     expect(render.mock.calls[1][0].values.foo).toBeUndefined()
 
     expect(renderInput).toHaveBeenCalled()
-    expect(renderInput).toHaveBeenCalledTimes(1)
-    expect(renderInput.mock.calls[0][0].input.value).toBeUndefined()
+    expect(renderInput).toHaveBeenCalledTimes(2)
+    expect(renderInput.mock.calls[1][0].input.value).toBeUndefined()
 
     renderInput.mock.calls[0][0].input.onChange('bar')
 
-    expect(renderInput).toHaveBeenCalledTimes(2)
-    expect(renderInput.mock.calls[1][0].input.value).toBe('bar')
+    expect(renderInput).toHaveBeenCalledTimes(4)
+    expect(renderInput.mock.calls[3][0].input.value).toBe('bar')
   })
 
   it('should provide a value of [] when empty on a select multiple', () => {
@@ -322,18 +322,18 @@ describe('Field', () => {
     )
 
     expect(renderInput).toHaveBeenCalled()
-    expect(renderInput).toHaveBeenCalledTimes(1)
-    expect(renderInput.mock.calls[0][0].input.value).toBe('')
+    expect(renderInput).toHaveBeenCalledTimes(2)
+    expect(renderInput.mock.calls[1][0].input.value).toBe('')
 
     renderInput.mock.calls[0][0].input.onChange('bar')
 
-    expect(renderInput).toHaveBeenCalledTimes(2)
-    expect(renderInput.mock.calls[1][0].input.value).toBe('bar')
+    expect(renderInput).toHaveBeenCalledTimes(4)
+    expect(renderInput.mock.calls[3][0].input.value).toBe('bar')
 
     renderInput.mock.calls[1][0].input.onChange(null)
 
-    expect(renderInput).toHaveBeenCalledTimes(3)
-    expect(renderInput.mock.calls[2][0].input.value).toBe('')
+    expect(renderInput).toHaveBeenCalledTimes(6)
+    expect(renderInput.mock.calls[5][0].input.value).toBe('')
   })
 
   it('should optionally allow null values', () => {
@@ -451,22 +451,22 @@ describe('Field', () => {
     onChange('hi')
 
     // valid now
-    expect(input).toHaveBeenCalledTimes(3)
-    expect(input.mock.calls[2][0].meta.error).toBeUndefined()
+    expect(input).toHaveBeenCalledTimes(4)
+    expect(input.mock.calls[3][0].meta.error).toBeUndefined()
 
     // toggle rules
     const button = TestUtils.findRenderedDOMComponentWithTag(dom, 'button')
     TestUtils.Simulate.click(button)
 
     // props changed, but still valid. doesn't update until next time validation is run
-    expect(input).toHaveBeenCalledTimes(4)
-    expect(input.mock.calls[3][0].meta.error).toBeUndefined()
+    expect(input).toHaveBeenCalledTimes(5)
+    expect(input.mock.calls[4][0].meta.error).toBeUndefined()
 
     onChange('his')
 
     // invalid now
-    expect(input).toHaveBeenCalledTimes(5)
-    expect(input.mock.calls[4][0].meta.error).toBe('Must be uppercase')
+    expect(input).toHaveBeenCalledTimes(7)
+    expect(input.mock.calls[6][0].meta.error).toBe('Must be uppercase')
   })
 
   it('should render checkboxes with checked prop', () => {
diff --git a/src/FormSpy.test.js b/src/FormSpy.test.js
index 5d670b8..f644b98 100644
--- a/src/FormSpy.test.js
+++ b/src/FormSpy.test.js
@@ -47,24 +47,24 @@ describe('FormSpy', () => {
     expect(render.mock.calls[1][0].validating).toBe(false)
     expect(render.mock.calls[1][0].values).toEqual({})
     expect(renderInput).toHaveBeenCalled()
-    expect(renderInput).toHaveBeenCalledTimes(1)
+    expect(renderInput).toHaveBeenCalledTimes(2)
 
     // change value
     renderInput.mock.calls[0][0].input.onChange('bar')
 
-    expect(render).toHaveBeenCalledTimes(3)
-    hasFormApi(render.mock.calls[2][0])
-    expect(render.mock.calls[2][0].dirty).toBe(true)
-    expect(render.mock.calls[2][0].errors).toEqual({})
-    expect(render.mock.calls[2][0].invalid).toBe(false)
-    expect(render.mock.calls[2][0].pristine).toBe(false)
-    expect(render.mock.calls[2][0].submitFailed).toBe(false)
-    expect(render.mock.calls[2][0].submitSucceeded).toBe(false)
-    expect(render.mock.calls[2][0].submitting).toBe(false)
-    expect(render.mock.calls[2][0].valid).toBe(true)
-    expect(render.mock.calls[2][0].validating).toBe(false)
-    expect(render.mock.calls[2][0].values).toEqual({ foo: 'bar' })
-    expect(renderInput).toHaveBeenCalledTimes(2)
+    expect(render).toHaveBeenCalledTimes(4)
+    hasFormApi(render.mock.calls[3][0])
+    expect(render.mock.calls[3][0].dirty).toBe(true)
+    expect(render.mock.calls[3][0].errors).toEqual({})
+    expect(render.mock.calls[3][0].invalid).toBe(false)
+    expect(render.mock.calls[3][0].pristine).toBe(false)
+    expect(render.mock.calls[3][0].submitFailed).toBe(false)
+    expect(render.mock.calls[3][0].submitSucceeded).toBe(false)
+    expect(render.mock.calls[3][0].submitting).toBe(false)
+    expect(render.mock.calls[3][0].valid).toBe(true)
+    expect(render.mock.calls[3][0].validating).toBe(false)
+    expect(render.mock.calls[3][0].values).toEqual({ foo: 'bar' })
+    expect(renderInput).toHaveBeenCalledTimes(4)
   })
 
   it('should resubscribe if subscription changes', () => {
@@ -164,7 +164,7 @@ describe('FormSpy', () => {
     expect(render.mock.calls[1][0].validating).toBeUndefined()
     expect(render.mock.calls[1][0].values).toEqual({})
     expect(renderInput).toHaveBeenCalled()
-    expect(renderInput).toHaveBeenCalledTimes(1)
+    expect(renderInput).toHaveBeenCalledTimes(2)
 
     // change value
     renderInput.mock.calls[0][0].input.onChange('bar')
@@ -182,7 +182,7 @@ describe('FormSpy', () => {
     expect(render.mock.calls[3][0].valid).toBeUndefined()
     expect(render.mock.calls[3][0].validating).toBeUndefined()
     expect(render.mock.calls[3][0].values).toEqual({ foo: 'bar' })
-    expect(renderInput).toHaveBeenCalledTimes(2)
+    expect(renderInput).toHaveBeenCalledTimes(4)
   })
 
   it('should not unsubscribe/resubscribe if not in form', () => {
@@ -259,14 +259,14 @@ describe('FormSpy', () => {
       </Form>
     )
     expect(input).toHaveBeenCalled()
-    expect(input).toHaveBeenCalledTimes(1)
+    expect(input).toHaveBeenCalledTimes(2)
     expect(onChange).toHaveBeenCalled()
     expect(onChange).toHaveBeenCalledTimes(1)
     expect(onChange).toHaveBeenCalledWith({ dirty: false })
 
     input.mock.calls[0][0].input.onChange('bar')
 
-    expect(input).toHaveBeenCalledTimes(2)
+    expect(input).toHaveBeenCalledTimes(4)
     expect(onChange).toHaveBeenCalledTimes(2)
     expect(onChange).toHaveBeenCalledWith({ dirty: true })
   })