Skip to content

Commit 38b9b00

Browse files
authored
Fix form rerender bug (#498)
1 parent 34b289b commit 38b9b00

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

src/ReactFinalForm.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,17 @@ const ReactFinalForm = ({
7878
}
7979
)
8080

81+
// save a copy of state that can break through the closure
82+
// on the shallowEqual() line below.
83+
const stateRef = React.useRef<FormState>(state)
84+
stateRef.current = state
85+
8186
React.useEffect(() => {
8287
// We have rendered, so all fields are no registered, so we can unpause validation
8388
form.isValidationPaused() && form.resumeValidation()
8489
const unsubscriptions: Unsubscribe[] = [
8590
form.subscribe(s => {
86-
if (!shallowEqual(s, state)) {
91+
if (!shallowEqual(s, stateRef.current)) {
8792
setState(s)
8893
}
8994
}, subscription),

src/ReactFinalForm.test.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react'
2-
import { render, fireEvent, cleanup, act } from 'react-testing-library'
2+
import { render, fireEvent, cleanup } from 'react-testing-library'
33
import 'jest-dom/extend-expect'
44
import deepEqual from 'fast-deep-equal'
55
import { ErrorBoundary, Toggle, wrapWith } from './testUtils'
@@ -857,4 +857,54 @@ describe('ReactFinalForm', () => {
857857
expect(onSubmitMock).toHaveBeenCalledTimes(1)
858858
expect(onSubmitMock.mock.calls[0][0]).toEqual({ name: 'erikras' })
859859
})
860+
861+
it('should set submitting back to false after submit', async () => {
862+
/**
863+
* This test causes a warning:
864+
*
865+
* Warning: An update to ReactFinalForm inside a test was not wrapped in act(...).
866+
*
867+
* ...but it's working as expected:
868+
* 1) We click "Submit"
869+
* 2) Submission is async and takes 1ms
870+
* 3) The form's state has to go to `submitting = true` and then back to `submitting = false`
871+
*
872+
* That state change when the submission completes is not an "act" from the
873+
* user, but an internal state change. If you have an idea of how to fix this,
874+
* please submit a PR. Thanks. -@erikras
875+
*/
876+
const onSubmit = jest.fn(async () => {
877+
sleep(1)
878+
})
879+
const recordSubmitting = jest.fn()
880+
const { getByText } = render(
881+
<Form onSubmit={onSubmit} subscription={{ submitting: true }}>
882+
{({ handleSubmit, submitting }) => {
883+
recordSubmitting(submitting)
884+
return (
885+
<form onSubmit={handleSubmit}>
886+
<Field name="name" component="input" />
887+
<button type="submit">Submit</button>
888+
</form>
889+
)
890+
}}
891+
</Form>
892+
)
893+
expect(onSubmit).not.toHaveBeenCalled()
894+
expect(recordSubmitting).toHaveBeenCalled()
895+
expect(recordSubmitting).toHaveBeenCalledTimes(1)
896+
expect(recordSubmitting.mock.calls[0][0]).toBe(false)
897+
898+
fireEvent.click(getByText('Submit'))
899+
900+
expect(onSubmit).toHaveBeenCalled()
901+
expect(onSubmit).toHaveBeenCalledTimes(1)
902+
expect(recordSubmitting).toHaveBeenCalledTimes(2)
903+
expect(recordSubmitting.mock.calls[1][0]).toBe(true)
904+
905+
await sleep(5)
906+
907+
expect(recordSubmitting).toHaveBeenCalledTimes(3)
908+
expect(recordSubmitting.mock.calls[2][0]).toBe(false)
909+
})
860910
})

0 commit comments

Comments
 (0)