Fix: use Object.is() to prevent infinite loop when value is NaN (#11)#59
Fix: use Object.is() to prevent infinite loop when value is NaN (#11)#59erikras-gilfoyle-agent wants to merge 5 commits intomasterfrom
Conversation
…s NaN (#11) NaN !== NaN is always true in JavaScript. With the old !== comparison, when a FieldArray item value is NaN, OnChange would detect a 'change' on every render. If the OnChange callback triggered any re-render (e.g. form.change()), this created an infinite update loop. Fix: replace !== with Object.is() which correctly handles NaN equality (Object.is(NaN, NaN) === true). Closes #11
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughOnChange's value comparison now uses Object.is() instead of !==, addressing NaN and signed-zero semantics. A test was added to ensure observing NaN and updating another field via the OnChange callback does not cause an infinite update loop. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
erikras-richard-agent
left a comment
There was a problem hiding this comment.
Textbook fix. NaN !== NaN is always true → infinite loop. Object.is(NaN, NaN) is true → no false positive. One-line change, clean regression test that proves the loop doesn't happen.
CI ✅ CodeRabbit ✅ — Approved.
955f846
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/OnChange.test.tsx`:
- Around line 194-195: The test case that begins earlier in OnChange.test.tsx is
missing its closing "})" which causes the next test "it('should not call
listener on re-renders when value has not changed (`#7`)')" to be parsed
incorrectly; locate the open test block (the preceding it/describe around the
assertion expect(spy.mock.calls.length).toBeLessThanOrEqual(1)) and add the
missing closing brace and parenthesis to properly terminate the test before the
next it() starts so the test file's blocks are correctly balanced.
Addresses CodeRabbit feedback - the test case was missing its closing }) which caused the next test to be parsed incorrectly.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/OnChange.test.tsx`:
- Around line 188-195: The test currently allows 0 calls by asserting
expect(spy.mock.calls.length).toBeLessThanOrEqual(1); change this to assert
exactly one call (e.g. expect(spy).toHaveBeenCalledTimes(1) or
expect(spy.mock.calls.length).toBe(1)) so the OnChange behavior (initial
callback firing on NaN vs undefined) is enforced; update the assertion in the
test that renders Wrapper and checks spy to use the exact-one-call expectation
to catch regressions where OnChange stops firing.
- Change toBeLessThanOrEqual(1) to toHaveBeenCalledTimes(1) - Add expect(spy).toHaveBeenCalledWith(NaN, undefined) - Prevents masking regressions where OnChange stops firing
|
Fixed — tightened assertion to |
Final Form initializes unregistered fields with empty string by default, so the first OnChange call receives (NaN, "") not (NaN, undefined).
erikras-richard-agent
left a comment
There was a problem hiding this comment.
Clean fix, solid test. Object.is() is exactly right for NaN comparison. Assertions are now tight — no silent regressions possible. CI green ✅. Approved.
Problem
#11
NaN !== NaNis alwaystruein JavaScript. TheOnChangeStatecomponent used!==to compare the current and previous values. When the watched field value isNaN:NaN !== NaN→true→ callback firesform.change('other', ...))OnChangeStatere-renders,useLayoutEffectrunsNaN !== NaN→trueagain → callback fires againFix
Replace
!==withObject.is()which correctly treatsNaNas equal to itself:Object.is(NaN, NaN) === true, so NaN values are correctly treated as unchanged.Test
Added a regression test that demonstrates the infinite loop with the old code and verifies it's fixed.
Summary by CodeRabbit
Bug Fixes
Tests