Repository: final-form/react-final-form
Pull request #149 (2018-02-09 06:15:01)

Activating Open Collective
This pull request adds backers and sponsors from your Open Collective https://opencollective.com/react-final-form ❤️
  
  It adds two badges at the top to show the latest number of backers and sponsors. It also adds placeholders so that the avatar/logo of new backers/sponsors can automatically be shown without having to update your README.md. [[more info](https://github.com/opencollective/opencollective/wiki/Github-banner)]. See how it looks on [this repo](https://github.com/apex/apex#backers).
We have also added a `postinstall` script to let people know after `npm|yarn install` that you are welcoming donations (optional). [[More info](https://github.com/OpenCollective/opencollective-cli)]
You can also add a "Donate" button to your website and automatically show your backers and sponsors there with our widgets. Have a look here: https://opencollective.com/widgets

  P.S: As with any pull request, feel free to comment or suggest changes. The only thing "required" are the placeholders on the README because we believe it's important to acknowledge the people in your community that are contributing (financially or with code!).

  Thank you for your great contribution to the open source community. You are awesome! 🙌
  And welcome to the open collective community! 😊

  Come chat with us in the #opensource channel on https://slack.opencollective.com - great place to ask questions and share best practices with other open source sustainers!
  

codecov[bot]: # [Codecov](https://codecov.io/gh/final-form/react-final-form/pull/149?src=pr&el=h1) Report
> Merging [#149](https://codecov.io/gh/final-form/react-final-form/pull/149?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/149/graphs/tree.svg?height=150&width=650&token=s8VUe6IxMZ&src=pr)](https://codecov.io/gh/final-form/react-final-form/pull/149?src=pr&el=tree)

```diff
@@          Coverage Diff          @@
##           master   #149   +/-   ##
=====================================
  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/149?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/149?src=pr&el=footer). Last update [ac4f535...cd1593b](https://codecov.io/gh/final-form/react-final-form/pull/149?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

erikras: Wow, that `contributors.svg` is awesome!

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


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 })
   })