Skip to content

fix(solid-form): prevent full array re-renders in array mode#2169

Merged
crutchcorn merged 3 commits into
mainfrom
fix-solid-array-mode
May 10, 2026
Merged

fix(solid-form): prevent full array re-renders in array mode#2169
crutchcorn merged 3 commits into
mainfrom
fix-solid-array-mode

Conversation

@crutchcorn
Copy link
Copy Markdown
Member

@crutchcorn crutchcorn commented May 10, 2026

Mirrors #1963 but for the Solid.js adapter

Summary by CodeRabbit

  • Documentation

    • Clarified example to explicitly declare an array-mode field in the form guide.
  • Bug Fixes

    • Prevented unnecessary full re-renders for array-mode fields, improving performance.
  • Tests

    • Added test coverage validating array-mode field reactivity and updates.
  • Chores

    • Added a patch changeset for the solid-form release.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 10, 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: f84e3036-4e18-4fdf-a9dd-6ee45367ec61

📥 Commits

Reviewing files that changed from the base of the PR and between 8c4f75d and 3438a77.

📒 Files selected for processing (1)
  • packages/solid-form/src/createField.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/solid-form/src/createField.tsx

📝 Walkthrough

Walkthrough

This PR makes Solid form fields mode-aware for arrays: exports FieldOptionsMode, updates makeFieldReactive to accept mode and subscribe to array length in array mode (full value otherwise), updates examples/docs to use mode="array", adds a test, and adds a changeset.

Changes

Array Mode Support for Solid Form Fields

Layer / File(s) Summary
Type Contract
packages/solid-form/src/types.ts
FieldOptionsMode is exported with @private JSDoc and optional `mode?: 'value'
Imports / Signature
packages/solid-form/src/createField.tsx
Adds FieldOptionsMode to imports and updates makeFieldReactive signature to accept { mode }: FieldOptionsMode.
Core Reactivity Implementation
packages/solid-form/src/createField.tsx
makeFieldReactive implements mode-aware subscriptions: array mode tracks array.length; value mode tracks full value; meta fields (isTouched, isBlurred, isDirty, errorMap, errorSourceMap, isValidating) are tracked individually. createField passes options.mode.
Usage Examples
examples/solid/array/src/index.tsx, docs/framework/solid/guides/arrays.md
Example and docs updated to declare mode="array" on the people form field.
Tests
packages/solid-form/tests/createField.test.tsx
New test asserts initial ["a"] rendering and updates to ["a","b"] after pushValue('b').
Changeset
.changeset/dull-baboons-like.md
Adds a patch changeset noting prevention of full array re-renders in array mode.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit hops through form fields bright,
Array mode trims re-renders light,
Length is watched, not every nested part,
Meta flags still beat with faithful heart,
🐰✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is too brief and does not follow the required template structure with 'Changes' and 'Checklist' sections. Expand the description to include the 'Changes' section explaining what was changed and why, and complete the required checklist items.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: preventing full array re-renders in array mode for the solid-form package.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-solid-array-mode

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.

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented May 10, 2026

View your CI Pipeline Execution ↗ for commit 5f945e4

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

☁️ Nx Cloud last updated this comment at 2026-05-10 21:01:57 UTC

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 10, 2026

🚀 Changeset Version Preview

3 package(s) bumped directly, 11 bumped as dependents.

🟨 Minor bumps

Package Version Reason
@tanstack/form-core 1.31.0 → 1.32.0 Changeset
@tanstack/solid-form 1.31.0 → 1.32.0 Changeset
@tanstack/vue-form 1.31.0 → 1.32.0 Changeset
@tanstack/angular-form 1.31.0 → 1.32.0 Dependent
@tanstack/react-form 1.31.0 → 1.32.0 Dependent
@tanstack/react-form-nextjs 1.31.0 → 1.32.0 Dependent
@tanstack/react-form-remix 1.31.0 → 1.32.0 Dependent
@tanstack/react-form-start 1.31.0 → 1.32.0 Dependent
@tanstack/svelte-form 1.31.0 → 1.32.0 Dependent

🟩 Patch bumps

Package Version Reason
@tanstack/form-devtools 0.2.26 → 0.2.27 Dependent
@tanstack/lit-form 1.24.0 → 1.24.1 Dependent
@tanstack/preact-form 1.29.6 → 1.29.7 Dependent
@tanstack/react-form-devtools 0.2.26 → 0.2.27 Dependent
@tanstack/solid-form-devtools 0.2.26 → 0.2.27 Dependent

Copy link
Copy Markdown

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/solid-form/src/createField.tsx (1)

90-130: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: mode variable is not defined in scope.

The function makeFieldReactive declares only one parameter fieldApi (lines 90–130), but line 177 references mode directly, which is not in scope. Additionally, line 331 calls makeFieldReactive(extendedApi as never, options.mode) with two arguments, but the function signature accepts only one.

Fix: Add mode as a second parameter to makeFieldReactive:

🐛 Proposed fix

Update the function signature to accept mode as a second parameter:

 >(
   fieldApi: FieldApi<
     // ... (type parameters omitted for brevity)
   > &
     SolidFieldApi<
       // ...
     > &
-    FieldOptionsMode,
+    FieldOptionsMode,
+  mode?: 'value' | 'array',
 ): () => FieldApi<

Alternatively, if mode should be accessed from fieldApi:

   const reactiveStateValue = useStore(fieldApi.store, (state) =>
-    mode === 'array'
+    fieldApi.mode === 'array'
       ? Object.keys((state.value as unknown) ?? []).length
       : state.value,
   )

And update the call site:

-  >(extendedApi as never, options.mode)
+  >(Object.assign(extendedApi, { mode: options.mode }) as never)

Also applies to: 170-180

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/solid-form/src/createField.tsx` around lines 90 - 130, The function
makeFieldReactive currently only accepts fieldApi but references mode and is
invoked with two args (e.g., makeFieldReactive(extendedApi as never,
options.mode)); fix by adding a second parameter named mode to
makeFieldReactive's signature and use that parameter instead of referencing an
undefined variable, and update any call sites to pass the correct options.mode
(or alternatively read mode from fieldApi if intended) — ensure references
inside makeFieldReactive and all invocations (such as the call with extendedApi
and options.mode) are consistent with the new two-argument signature.
🧹 Nitpick comments (1)
packages/solid-form/tests/createField.test.tsx (1)

571-597: ⚖️ Poor tradeoff

Consider testing the array-length optimization.

The current test verifies that array mode works, but doesn't confirm that the optimization (tracking array length instead of full value) prevents unnecessary re-renders when nested properties change.

Consider adding a test that mutates a nested property and verifies the parent field doesn't re-render.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/solid-form/tests/createField.test.tsx` around lines 571 - 597, Add a
new test that verifies the array-length optimization prevents parent re-renders
when a nested item is mutated: render a component using createForm with
defaultValues.test = [{ x: 1 }] and a form.Field name="test" mode="array" that
increments a render counter (ref or jest.fn) each render and displays
field().state.value; then mutate a nested property on the first item via the
nested-field API (e.g., call the nested item's setter / setValue / setAt) and
assert the nested item updates but the parent field's render counter did not
increment (i.e., parent did not re-render), while ensuring the visible nested
value changed; reference createForm, form.Field, mode="array",
field().state.value and the nested field setter when adding this assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/solid-form/src/createField.tsx`:
- Around line 90-130: The function makeFieldReactive currently only accepts
fieldApi but references mode and is invoked with two args (e.g.,
makeFieldReactive(extendedApi as never, options.mode)); fix by adding a second
parameter named mode to makeFieldReactive's signature and use that parameter
instead of referencing an undefined variable, and update any call sites to pass
the correct options.mode (or alternatively read mode from fieldApi if intended)
— ensure references inside makeFieldReactive and all invocations (such as the
call with extendedApi and options.mode) are consistent with the new two-argument
signature.

---

Nitpick comments:
In `@packages/solid-form/tests/createField.test.tsx`:
- Around line 571-597: Add a new test that verifies the array-length
optimization prevents parent re-renders when a nested item is mutated: render a
component using createForm with defaultValues.test = [{ x: 1 }] and a form.Field
name="test" mode="array" that increments a render counter (ref or jest.fn) each
render and displays field().state.value; then mutate a nested property on the
first item via the nested-field API (e.g., call the nested item's setter /
setValue / setAt) and assert the nested item updates but the parent field's
render counter did not increment (i.e., parent did not re-render), while
ensuring the visible nested value changed; reference createForm, form.Field,
mode="array", field().state.value and the nested field setter when adding this
assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6607fe6c-9dfd-469d-a578-fb5e3260a148

📥 Commits

Reviewing files that changed from the base of the PR and between e216d18 and 5f945e4.

📒 Files selected for processing (5)
  • docs/framework/solid/guides/arrays.md
  • examples/solid/array/src/index.tsx
  • packages/solid-form/src/createField.tsx
  • packages/solid-form/src/types.ts
  • packages/solid-form/tests/createField.test.tsx

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 10, 2026

More templates

@tanstack/angular-form

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

@tanstack/form-core

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

@tanstack/form-devtools

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

@tanstack/lit-form

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

@tanstack/preact-form

npm i https://pkg.pr.new/@tanstack/preact-form@2169

@tanstack/react-form

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

@tanstack/react-form-devtools

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

@tanstack/react-form-nextjs

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

@tanstack/react-form-remix

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

@tanstack/react-form-start

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

@tanstack/solid-form

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

@tanstack/solid-form-devtools

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

@tanstack/svelte-form

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

@tanstack/vue-form

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

commit: 3438a77

@sentry
Copy link
Copy Markdown

sentry Bot commented May 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.65%. Comparing base (6892ed0) to head (3438a77).
⚠️ Report is 206 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2169      +/-   ##
==========================================
+ Coverage   90.35%   97.65%   +7.30%     
==========================================
  Files          38        4      -34     
  Lines        1752      128    -1624     
  Branches      444       12     -432     
==========================================
- Hits         1583      125    -1458     
+ Misses        149        3     -146     
+ Partials       20        0      -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.

@crutchcorn crutchcorn merged commit 19c3ec2 into main May 10, 2026
9 checks passed
@crutchcorn crutchcorn deleted the fix-solid-array-mode branch May 10, 2026 21:03
@github-actions github-actions Bot mentioned this pull request May 10, 2026
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.

1 participant