jaredpalmer / jaredpalmer/formik
helpers.setValue causes infinite loop when called inside useEffect in React 18
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 34.3k
- Forks
- 2.8k
- PR merge metrics
- No merged PRs in 30d
Description
## Bug report
Calling `helpers.setValue` results in an infinite loop when it's called inside useEffect in React 18.
React 17: https://codesandbox.io/s/formik-usefield-hook-react-18-bug-forked-ucpg4d?file=/src/App.js
React 18: https://codesandbox.io/s/formik-usefield-hook-react-18-bug-nr052g?file=/src/App.js
The code of the `App` component is exactly the same on both sandboxes, what changes is the React major version.
### Expected behavior
React 17: If you click on the `CLICK` button in the React 17 sandbox, you will see that the input value will change from `aaa@mail.com` to `bbb@mail.com` 🆗 ✅
### Current Behavior
React 18: If you click on the `CLICK` button in the React 18 sandbox, it will cause an infinite loop ⚠️❗
### Suggested solution(s)
I don't know exactly what could be the root cause of this issue, but I suspect that it's related to the **Automatic Batching** feature/breaking change introduced by React 18:
https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#automatic-batching
What happens in practice is that the reducer for `SET_FIELD_VALUE` is never called for some reason, even though it's action gets dispatched within the `setFieldValue` function.
The reducer for `SET_ISVALIDATING` is executed instead.
On React 17:
- Formik's `setFieldValue` is called;
- dispatch `SET_FIELD_VALUE`
- Reducer for `SET_FIELD_VALUE` is executed
- `validateFormWithHightPriority` is then executed ✅
On React 18:
- Formik's `setFieldValue` is called;
- dispatch `SET_FIELD_VALUE`
- `validateFormWithHightPriority` is executed ❗
- Reducer for `SET_ISVALIDATING` is executed
- Reducer for `SET_FIELD_VALUE` is never executed for some reason ⚠️
The infinite loop is then caused by the `useField` hook always returning the old value instead of the new value that was set through `helpers.setValue(value)`.



### Your environment
| Software | Version(s) |
| ---------------- | ---------- |
| Formik | 2.2.9
| React | 18.2.0
| TypeScript | -
| Browser | Chrome
| npm/Yarn | Yarn
| Operating System | Mac OS X
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked React 17 and React 18 CodeSandbox reproductions, then trace Formik's setFieldValue, useField, and reducer flow described in the report. Done means the React 18 example updates the input from aaa@mail.com to bbb@mail.com without entering an infinite loop, while preserving the React 17 behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100