Skip to content

Commit c8eb275

Browse files
authored
Revert "Revert "Added onChange prop to FormSpy (#42)" (#43)" (#44)
This reverts commit c13032e.
1 parent c13032e commit c8eb275

File tree

5 files changed

+119
-11
lines changed

5 files changed

+119
-11
lines changed

README.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
✅ Opt-in subscriptions - only update on the state you need!
1717

18-
✅ 💥 **2.2k gzipped** 💥
18+
✅ 💥 **2.5k gzipped** 💥
1919

2020
---
2121

@@ -177,8 +177,9 @@ const MyForm = () => (
177177
* [`FormSpyProps`](#formspyprops)
178178
* [`children?: ((props: FormSpyRenderProps) => React.Node) | React.Node`](#children-props-formspyrenderprops--reactnode--reactnode)
179179
* [`component?: React.ComponentType<FormSpyRenderProps>`](#component-reactcomponenttypeformspyrenderprops)
180+
* [`onChange?: (formState: FormState) => void`](#onchange-formstate-formstate--void)
180181
* [`render?: (props: FormSpyRenderProps) => React.Node`](#render-props-formspyrenderprops--reactnode)
181-
* [`formSubscription?: FormSubscription`](#formsubscription-formsubscription)
182+
* [`subscription?: FormSubscription`](#subscription-formsubscription-1)
182183
* [`FormSpyRenderProps`](#formspyrenderprops)
183184

184185
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -538,19 +539,28 @@ of the ways to render: `component`, `render`, or `children`.
538539
#### `children?: ((props: FormSpyRenderProps) => React.Node) | React.Node`
539540

540541
A render function that is given [`FormSpyRenderProps`](#formspyrenderprops), as
541-
well as any non-API props passed into the `<FormSpy/>` component.
542+
well as any non-API props passed into the `<FormSpy/>` component. Will not be
543+
called if an `onChange` prop is provided.
542544

543545
#### `component?: React.ComponentType<FormSpyRenderProps>`
544546

545547
A component that is given [`FormSpyRenderProps`](#formspyrenderprops) as props,
546-
as well as any non-API props passed into the `<FormSpy/>` component.
548+
as well as any non-API props passed into the `<FormSpy/>` component. Will not be
549+
called if an `onChange` prop is provided.
550+
551+
#### `onChange?: (formState: FormState) => void`
552+
553+
A change listener that will be called with form state whenever the form state,
554+
as subscribed to by the `subscription` prop, has changed. When an `onChange`
555+
prop is provided, the `<FormSpy/>` will not render anything.
547556

548557
#### `render?: (props: FormSpyRenderProps) => React.Node`
549558

550559
A render function that is given [`FormSpyRenderProps`](#formspyrenderprops), as
551-
well as any non-API props passed into the `<FormSpy/>` component.
560+
well as any non-API props passed into the `<FormSpy/>` component. Will not be
561+
called if an `onChange` prop is provided.
552562

553-
#### `formSubscription?: FormSubscription`
563+
#### `subscription?: FormSubscription`
554564

555565
A
556566
[`FormSubscription`](https://github.com/final-form/final-form#formsubscription--string-boolean-)

docs/comparison.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ and you'd like it to be), please correct the mistake.
66

77
| Feature | [🏁 React-Final-Form](https://github.com/final-form/react-final-form#-react-final-form) | [Formik](https://github.com/jaredpalmer/formik) | [Redux-Form](https://github.com/erikras/redux-form) |
88
| ------------------------------------- | :---------------------------------------------------------------------------------------------------------------: | :----------------------------------------------: | :---------------------------------------------------: |
9-
| Bundle Size | [3.5k](https://bundlephobia.com/result?p=final-form) + [2.2k](https://bundlephobia.com/result?p=react-final-form) | [7.5k](https://bundlephobia.com/result?p=formik) | [26.8k](https://bundlephobia.com/result?p=redux-form) |
9+
| Bundle Size | [3.5k](https://bundlephobia.com/result?p=final-form) + [2.5k](https://bundlephobia.com/result?p=react-final-form) | [7.5k](https://bundlephobia.com/result?p=formik) | [26.8k](https://bundlephobia.com/result?p=redux-form) |
1010
| Works without Redux ||||
1111
| Record-Level Sync Validation ||||
1212
| Record-Level Async Validation ||||

src/FormSpy.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ export default class FormSpy extends React.PureComponent<Props, State> {
3131
this.notify(state)
3232
} else {
3333
initialState = state
34+
if (props.onChange) {
35+
props.onChange(state)
36+
}
3437
}
3538
})
3639
}
@@ -47,7 +50,12 @@ export default class FormSpy extends React.PureComponent<Props, State> {
4750
)
4851
}
4952

50-
notify = (state: FormState) => this.setState({ state })
53+
notify = (state: FormState) => {
54+
this.setState({ state })
55+
if (this.props.onChange) {
56+
this.props.onChange(state)
57+
}
58+
}
5159

5260
componentWillReceiveProps(nextProps: Props) {
5361
const { subscription } = nextProps
@@ -71,8 +79,10 @@ export default class FormSpy extends React.PureComponent<Props, State> {
7179
}
7280

7381
render() {
74-
const { subscription, ...rest } = this.props
75-
return renderComponent({ ...rest, ...this.state.state }, 'FormSpy')
82+
const { onChange, subscription, ...rest } = this.props
83+
return onChange
84+
? null
85+
: renderComponent({ ...rest, ...this.state.state }, 'FormSpy')
7686
}
7787
}
7888

src/FormSpy.test.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,4 +202,91 @@ describe('FormSpy', () => {
202202
const button = TestUtils.findRenderedDOMComponentWithTag(dom, 'button')
203203
TestUtils.Simulate.click(button)
204204
})
205+
206+
it('should call onChange', () => {
207+
const input = jest.fn(({ input }) => <input {...input} />)
208+
const onChange = jest.fn()
209+
TestUtils.renderIntoDocument(
210+
<Form onSubmit={onSubmitMock}>
211+
{() => (
212+
<form>
213+
<FormSpy subscription={{ dirty: true }} onChange={onChange} />
214+
<Field name="foo" render={input} />
215+
</form>
216+
)}
217+
</Form>
218+
)
219+
expect(input).toHaveBeenCalled()
220+
expect(input).toHaveBeenCalledTimes(1)
221+
expect(onChange).toHaveBeenCalled()
222+
expect(onChange).toHaveBeenCalledTimes(1)
223+
expect(onChange).toHaveBeenCalledWith({ dirty: false })
224+
225+
input.mock.calls[0][0].input.onChange('bar')
226+
227+
expect(input).toHaveBeenCalledTimes(2)
228+
expect(onChange).toHaveBeenCalledTimes(2)
229+
expect(onChange).toHaveBeenCalledWith({ dirty: true })
230+
})
231+
232+
it('should not render with render prop when given onChange', () => {
233+
const onChange = jest.fn()
234+
const render = jest.fn()
235+
TestUtils.renderIntoDocument(
236+
<Form onSubmit={onSubmitMock}>
237+
{() => (
238+
<form>
239+
<FormSpy
240+
subscription={{ dirty: true }}
241+
onChange={onChange}
242+
render={render}
243+
/>
244+
</form>
245+
)}
246+
</Form>
247+
)
248+
expect(onChange).toHaveBeenCalled()
249+
expect(onChange).toHaveBeenCalledTimes(1)
250+
expect(render).not.toHaveBeenCalled()
251+
})
252+
253+
it('should not render with child render prop when given onChange', () => {
254+
const onChange = jest.fn()
255+
const render = jest.fn()
256+
TestUtils.renderIntoDocument(
257+
<Form onSubmit={onSubmitMock}>
258+
{() => (
259+
<form>
260+
<FormSpy subscription={{ dirty: true }} onChange={onChange}>
261+
{render}
262+
</FormSpy>
263+
</form>
264+
)}
265+
</Form>
266+
)
267+
expect(onChange).toHaveBeenCalled()
268+
expect(onChange).toHaveBeenCalledTimes(1)
269+
expect(render).not.toHaveBeenCalled()
270+
})
271+
272+
it('should not render with component prop when given onChange', () => {
273+
const onChange = jest.fn()
274+
const render = jest.fn()
275+
TestUtils.renderIntoDocument(
276+
<Form onSubmit={onSubmitMock}>
277+
{() => (
278+
<form>
279+
<FormSpy
280+
subscription={{ dirty: true }}
281+
onChange={onChange}
282+
component={render}
283+
/>
284+
</form>
285+
)}
286+
</Form>
287+
)
288+
expect(onChange).toHaveBeenCalled()
289+
expect(onChange).toHaveBeenCalledTimes(1)
290+
expect(render).not.toHaveBeenCalled()
291+
})
205292
})

src/types.js.flow

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export type FormRenderProps = {
4646
reset: () => void
4747
} & FormState
4848

49-
export type FormSpyRenderProps = {} & FormState
49+
export type FormSpyRenderProps = FormState
5050

5151
export type RenderableProps<T> = $Shape<{
5252
children: ((props: T) => React.Node) | React.Node,
@@ -68,5 +68,6 @@ export type FieldProps = {
6868
} & RenderableProps<FieldRenderProps>
6969

7070
export type FormSpyProps = {
71+
onChange?: (formState: FormState) => void,
7172
subscription?: FormSubscription
7273
} & RenderableProps<FormSpyRenderProps>

0 commit comments

Comments
 (0)