Skip to content

fix(form-core): 🐛 File input field - Picking a different file does not trigger rerender (deep equality issue with File/Blob objects)#1939

Open
joaoGabriel55 wants to merge 11 commits intoTanStack:mainfrom
joaoGabriel55:fix/file-input-field-picking-a-different-file-does-not-trigger-rerender
Open

fix(form-core): 🐛 File input field - Picking a different file does not trigger rerender (deep equality issue with File/Blob objects)#1939
joaoGabriel55 wants to merge 11 commits intoTanStack:mainfrom
joaoGabriel55:fix/file-input-field-picking-a-different-file-does-not-trigger-rerender

Conversation

@joaoGabriel55
Copy link

@joaoGabriel55 joaoGabriel55 commented Dec 15, 2025

🎯 Changes

Issue: #1932

Fix: File input field — picking a different file does not trigger rerender due to deep equality issue with File/Blob objects.

Root cause: Object.keys(new File(...)) returns [] (empty array). The evaluate() function compares objects by iterating over Object.keys, so two different File instances with zero own enumerable keys are considered "equal" — the for-loop vacuously succeeds. This means setFieldValue with a new File doesn't trigger a state change.

Fix: Add a Blob guard in evaluate() (placed after the Object.is referential check and null checks, but before the generic key comparison). Since File extends Blob, this catches both types. If two Blob/File objects are the same reference, Object.is already returns true upstream. If they're different references, we return false — correctly triggering a rerender.

React Native compatibility: The guard uses typeof Blob !== 'undefined' to prevent ReferenceError in environments where Blob is not defined. If Blob doesn't exist, the check is skipped entirely — which is correct since no Blob objects can exist in that environment either.

Changes:

  • evaluate() in utils.ts: added Blob instance guard (+12 lines)
  • utils.spec.ts: added evaluate tests for File and Blob objects (same ref, different refs, nested in objects)
  • FormApi.spec.ts: added integration test for setFieldValue with File values

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • Bug Fixes

    • File and Blob comparisons in form change detection now use referential identity instead of key-based comparison, preventing false change events and preserving File/Blob instance semantics in form fields.
  • Tests

    • Added tests for File-type field updates and detailed File/Blob equality scenarios, covering same-reference and distinct-instance behaviors within fields and nested structures.
  • Chores

    • Recorded a patch-level changeset noting the fix.

@changeset-bot
Copy link

changeset-bot bot commented Dec 15, 2025

⚠️ No Changeset found

Latest commit: df74f02

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@nx-cloud
Copy link

nx-cloud bot commented Dec 17, 2025

View your CI Pipeline Execution ↗ for commit 452a71f

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 30s View ↗
nx run-many --target=build --exclude=examples/** ✅ Succeeded 1s View ↗

☁️ Nx Cloud last updated this comment at 2026-03-18 15:07:35 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 17, 2025

More templates

@tanstack/angular-form

npm i https://pkg.pr.new/@tanstack/angular-form@1939

@tanstack/form-core

npm i https://pkg.pr.new/@tanstack/form-core@1939

@tanstack/form-devtools

npm i https://pkg.pr.new/@tanstack/form-devtools@1939

@tanstack/lit-form

npm i https://pkg.pr.new/@tanstack/lit-form@1939

@tanstack/react-form

npm i https://pkg.pr.new/@tanstack/react-form@1939

@tanstack/react-form-devtools

npm i https://pkg.pr.new/@tanstack/react-form-devtools@1939

@tanstack/react-form-nextjs

npm i https://pkg.pr.new/@tanstack/react-form-nextjs@1939

@tanstack/react-form-remix

npm i https://pkg.pr.new/@tanstack/react-form-remix@1939

@tanstack/react-form-start

npm i https://pkg.pr.new/@tanstack/react-form-start@1939

@tanstack/solid-form

npm i https://pkg.pr.new/@tanstack/solid-form@1939

@tanstack/solid-form-devtools

npm i https://pkg.pr.new/@tanstack/solid-form-devtools@1939

@tanstack/svelte-form

npm i https://pkg.pr.new/@tanstack/svelte-form@1939

@tanstack/vue-form

npm i https://pkg.pr.new/@tanstack/vue-form@1939

commit: 452a71f

@codecov
Copy link

codecov bot commented Dec 17, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.17%. Comparing base (6892ed0) to head (452a71f).
⚠️ Report is 158 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1939      +/-   ##
==========================================
- Coverage   90.35%   90.17%   -0.19%     
==========================================
  Files          38       49      +11     
  Lines        1752     2015     +263     
  Branches      444      524      +80     
==========================================
+ Hits         1583     1817     +234     
- Misses        149      178      +29     
  Partials       20       20              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…trigger-rerender' of github-personal.com:joaoGabriel55/form into fix/file-input-field-picking-a-different-file-does-not-trigger-rerender
Copy link
Contributor

@LeCarbonator LeCarbonator left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the previous comment hasn't been addressed between the previous review and this review request.

The actual required changes don't look that bad, though. Perhaps I'll have some time to help out later this week with that.

@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1adf01bd-1895-4552-b18f-1594652d1ddd

📥 Commits

Reviewing files that changed from the base of the PR and between 05d7d94 and 452a71f.

📒 Files selected for processing (1)
  • .changeset/some-ducks-write.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • .changeset/some-ducks-write.md

📝 Walkthrough

Walkthrough

Treats Blob/File objects in form-core equality checks as referentially compared (avoid key-based comparison). Adds tests validating File/Blob equality semantics and form field behavior when setting File values.

Changes

Cohort / File(s) Summary
Core Blob/File Handling
packages/form-core/src/utils.ts
Add a special-case in the equality/evaluate logic to bypass key-based comparison when both operands are Blob/File-like, ensuring referential identity semantics.
Test Coverage
packages/form-core/tests/FormApi.spec.ts, packages/form-core/tests/utils.spec.ts
Add tests for File-type form field updates and File/Blob equality semantics (same-reference true; different instances false), including nested-structure cases.
Changeset
.changeset/some-ducks-write.md
Add changeset recording a patch: "Fix File/Blob equality in change detection".

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I nibble through bytes, not through keys,
Files keep their whiskers, untouched by peeks.
Same paw, same prize — otherwise apart,
Hopping light, I guard each file's heart.
A tiny patch, a joyful rabbit start.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing a File/Blob deep equality issue in form-core that prevented rerenders when selecting different files.
Description check ✅ Passed The description covers all required template sections with comprehensive detail: changes are explained with root cause analysis, checklist items are marked appropriately, and changeset generation is confirmed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
packages/form-core/tests/FormApi.spec.ts (1)

4104-4128: ⚠️ Potential issue | 🟡 Minor

Guard this test for runtimes where File is not globally available.

new File(...) on Line 4113 and Line 4119 will throw in environments without globalThis.File, so the test can fail before validating behavior.

Proposed patch
 it('should detect file value changes when setting a different File', () => {
+  if (typeof File === 'undefined') {
+    return
+  }
+
   const form = new FormApi({
     defaultValues: {
       avatar: undefined as File | undefined,
     },
   })
#!/bin/bash
set -euo pipefail

echo "== Node/runtime constraints =="
if [ -f package.json ]; then
  jq '.engines // {}, .volta // {}' package.json
fi

echo "== Vitest config files =="
fd -t f 'vitest.config.*|vite.config.*'

echo "== Test setup/environment hints =="
rg -n "environment|jsdom|happy-dom|globalThis\\.File|from 'node:buffer'|undici" -g "**/*vitest*.*" -g "**/*setup*.*" -g "**/*.ts"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/form-core/tests/FormApi.spec.ts` around lines 4104 - 4128, The test
constructs new File instances which will throw in runtimes without a global
File; guard the test by checking for File availability and skip or short-circuit
it when absent. Update the test around the usage of FormApi, setFieldValue and
getFieldValue so it only runs if typeof globalThis.File !== 'undefined' (or use
your test runner's skip mechanism) to avoid calling new File(...) in
environments that don't provide File.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/form-core/tests/FormApi.spec.ts`:
- Around line 4104-4128: The test constructs new File instances which will throw
in runtimes without a global File; guard the test by checking for File
availability and skip or short-circuit it when absent. Update the test around
the usage of FormApi, setFieldValue and getFieldValue so it only runs if typeof
globalThis.File !== 'undefined' (or use your test runner's skip mechanism) to
avoid calling new File(...) in environments that don't provide File.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5bb662cb-1e58-434d-9bfe-9395e9dd2c2a

📥 Commits

Reviewing files that changed from the base of the PR and between e21cc01 and 5ec30b3.

📒 Files selected for processing (3)
  • packages/form-core/src/utils.ts
  • packages/form-core/tests/FormApi.spec.ts
  • packages/form-core/tests/utils.spec.ts

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 @.changeset/some-ducks-write.md:
- Line 2: The changeset currently targets `@tanstack/react-form` but the bugfix
lives in form-core (the evaluate function in evaluate within
packages/form-core/src/utils.ts), so update the changeset to target
`@tanstack/form-core` (e.g., replace '@tanstack/react-form': patch with
'@tanstack/form-core': patch) so the core package is versioned and published;
keep the release type (patch) and ensure the changeset title/body reflect the
fix in evaluate to avoid releasing only the framework re-exports.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eb3ebf72-5caa-472c-af98-dc8df1658fc5

📥 Commits

Reviewing files that changed from the base of the PR and between 5ec30b3 and 05d7d94.

📒 Files selected for processing (1)
  • .changeset/some-ducks-write.md

@joaoGabriel55
Copy link
Author

Sorry for the delay with that @LeCarbonator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants