Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

refactor(query-core): improve replaceEqualDeep performance #9604

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Sheraff wants to merge 7 commits into TanStack:main
base: main
Choose a base branch
Loading
from Sheraff:refactor-query-core-replace-equal-deep-performance

Conversation

Copy link
Contributor

@Sheraff Sheraff commented Aug 31, 2025
edited by coderabbitai bot
Loading

This PR replicates the changes that were done in TanStack/router#5046.

TL;DR: Improve replaceEqualDeep performance by ~1.7x

How?

  • pre-allocate new arrays w/ their eventual size (new Array(bSize)), to avoid the memory management that happens under the hood every time we add an item to it
  • avoid re-reading the same value many times (a[key]) and instead store it as const aItem
  • use hasOwnProperty instead of creating a Set of the keys, because in theory hasOwnProperty is already O(1) for lookups, so we don't need to create an extra data structure for this

Benchmark

describe('replaceEqualDeep', () => {
 bench('old implementation', () => {
 replaceEqualDeepOld({ a: 1, b: [2, 3] }, { a: 1, b: [2, 3] })
 replaceEqualDeepOld({ a: 1, b: [2, 3] }, { a: 2, b: [2] })
 })
 bench('new implementation', () => {
 replaceEqualDeep({ a: 1, b: [2, 3] }, { a: 1, b: [2, 3] })
 replaceEqualDeep({ a: 1, b: [2, 3] }, { a: 2, b: [2] })
 })
})

Results

 ✓ @tanstack/query-core src/__tests__/utils.bench.ts > utils > replaceEqualDeep 1764ms
 name hz min max mean p75 p99 p995 p999 rme samples
 · old implementation 1,443,693.60 0.0006 0.1350 0.0007 0.0007 0.0009 0.0010 0.0017 ±0.12% 721847
 · new implementation 2,549,117.84 0.0003 0.1561 0.0004 0.0004 0.0005 0.0005 0.0009 ±0.09% 1274559 fastest
 BENCH Summary
 @tanstack/query-core new implementation - src/__tests__/utils.bench.ts > utils > replaceEqualDeep
 1.77x faster than old implementation

EDIT

latest commit has improved perf, but also 2x the amount of code

 ✓ @tanstack/query-core src/__tests__/utils.bench.ts > replaceEqualDeep 1868ms
 name hz min max mean p75 p99 p995 p999 rme samples
 · old implementation 1,425,853.65 0.0006 0.0827 0.0007 0.0007 0.0009 0.0010 0.0017 ±0.08% 712927
 · new implementation 3,922,005.11 0.0002 0.1265 0.0003 0.0003 0.0003 0.0004 0.0006 ±0.16% 1961003 fastest
 BENCH Summary
 @tanstack/query-core new implementation - src/__tests__/utils.bench.ts > replaceEqualDeep
 2.75x faster than old implementation

Summary by CodeRabbit

  • Bug Fixes

    • Improved deep-merge behavior for arrays and plain objects to avoid unnecessary updates and preserve unchanged values, preventing spurious state changes.
  • Refactor

    • Reworked deep-merge logic with stricter plain-object/array detection and added type safety checks for more reliable public API behavior and fewer allocations.

Copy link

coderabbitai bot commented Aug 31, 2025
edited
Loading

Walkthrough

Replaces previous replaceEqualDeep with a unified deep-merge handling arrays and plain objects, adds type guards (isPlainArray, isPlainObject) and a hasOwn alias, tightens plain-object detection, and widens exported typings to unknown/any.

Changes

Cohort / File(s) Summary
Deep-merge & typings
packages/query-core/src/utils.ts
Replaced replaceEqualDeep with a unified algorithm that: returns b for non-matching collection types, iterates b to build merged copies for arrays/plain objects, preserves identical items via strict-equality, recursively merges nested collections, and returns original a when fully equal. Added hasOwn = Object.prototype.hasOwnProperty, isPlainArray and isPlainObject type-guard predicates, stricter plain-object checks (prototype/constructor), and widened exported typings (unknown/any).

Sequence Diagram(s)

sequenceDiagram
 autonumber
 participant Caller
 participant Utils as replaceEqualDeep
 Caller->>Utils: replaceEqualDeep(a, b)
 alt not both arrays nor both plain objects
 Utils-->>Caller: return b
 else Arrays
 Note over Utils: build copy = new Array(b.length)
 loop for each index i
 Utils->>Utils: aItem = a[i]\nrecurse = replaceEqualDeep(aItem, b[i])
 alt aItem === b[i] or both undefined
 Note over Utils: equalItems++
 else
 Note over Utils: copy[i] = recurse
 end
 end
 alt lengths match and equalItems == a.length
 Utils-->>Caller: return a
 else
 Utils-->>Caller: return copy
 end
 else Plain Objects
 Note over Utils: build copy = {}
 loop for each own key in b
 Utils->>Utils: aItem = a[key]\nrecurse = replaceEqualDeep(aItem, b[key])
 alt aItem === b[key] or both undefined
 Note over Utils: equalItems++
 else
 Note over Utils: copy[key] = recurse
 end
 end
 alt own-key counts match and equalItems == aKeyCount
 Utils-->>Caller: return a
 else
 Utils-->>Caller: return copy
 end
 end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I hop through arrays and burrow in objects deep,
Counting equal footsteps where the old values keep.
With careful paws I check each key and strand,
Return the same if nothing changed, else stitch with my hand.
Thump-thump — a tidy merge from a rabbit’s leap. 🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

nx-cloud bot commented Aug 31, 2025
edited
Loading

🤖 Nx Cloud AI Fix Eligible

An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.

To disable these notifications, a workspace admin can disable them in workspace settings.


View your CI Pipeline Execution ↗ for commit 91494ca

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

☁️ Nx Cloud last updated this comment at 2025年09月01日 13:59:04 UTC

Copy link

pkg-pr-new bot commented Aug 31, 2025
edited
Loading

More templates
@tanstack/angular-query-devtools-experimental
npm i https://pkg.pr.new/@tanstack/angular-query-devtools-experimental@9604
@tanstack/angular-query-experimental
npm i https://pkg.pr.new/@tanstack/angular-query-experimental@9604
@tanstack/eslint-plugin-query
npm i https://pkg.pr.new/@tanstack/eslint-plugin-query@9604
@tanstack/query-async-storage-persister
npm i https://pkg.pr.new/@tanstack/query-async-storage-persister@9604
@tanstack/query-broadcast-client-experimental
npm i https://pkg.pr.new/@tanstack/query-broadcast-client-experimental@9604
@tanstack/query-core
npm i https://pkg.pr.new/@tanstack/query-core@9604
@tanstack/query-devtools
npm i https://pkg.pr.new/@tanstack/query-devtools@9604
@tanstack/query-persist-client-core
npm i https://pkg.pr.new/@tanstack/query-persist-client-core@9604
@tanstack/query-sync-storage-persister
npm i https://pkg.pr.new/@tanstack/query-sync-storage-persister@9604
@tanstack/react-query
npm i https://pkg.pr.new/@tanstack/react-query@9604
@tanstack/react-query-devtools
npm i https://pkg.pr.new/@tanstack/react-query-devtools@9604
@tanstack/react-query-next-experimental
npm i https://pkg.pr.new/@tanstack/react-query-next-experimental@9604
@tanstack/react-query-persist-client
npm i https://pkg.pr.new/@tanstack/react-query-persist-client@9604
@tanstack/solid-query
npm i https://pkg.pr.new/@tanstack/solid-query@9604
@tanstack/solid-query-devtools
npm i https://pkg.pr.new/@tanstack/solid-query-devtools@9604
@tanstack/solid-query-persist-client
npm i https://pkg.pr.new/@tanstack/solid-query-persist-client@9604
@tanstack/svelte-query
npm i https://pkg.pr.new/@tanstack/svelte-query@9604
@tanstack/svelte-query-devtools
npm i https://pkg.pr.new/@tanstack/svelte-query-devtools@9604
@tanstack/svelte-query-persist-client
npm i https://pkg.pr.new/@tanstack/svelte-query-persist-client@9604
@tanstack/vue-query
npm i https://pkg.pr.new/@tanstack/vue-query@9604
@tanstack/vue-query-devtools
npm i https://pkg.pr.new/@tanstack/vue-query-devtools@9604

commit: 91494ca

Copy link

codecov bot commented Aug 31, 2025
edited
Loading

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.48%. Comparing base (0650eaf) to head (d225d24).

Additional details and impacted files

Impacted file tree graph

@@ Coverage Diff @@
## main #9604 +/- ##
===========================================
+ Coverage 45.17% 59.48% +14.30% 
===========================================
 Files 208 137 -71 
 Lines 8327 5595 -2732 
 Branches 1878 1500 -378 
===========================================
- Hits 3762 3328 -434 
+ Misses 4118 1963 -2155 
+ Partials 447 304 -143 
Components Coverage Δ
@tanstack/angular-query-devtools-experimental ∅ <ø> (∅)
@tanstack/angular-query-experimental 87.00% <ø> (ø)
@tanstack/eslint-plugin-query ∅ <ø> (∅)
@tanstack/query-async-storage-persister 43.85% <ø> (ø)
@tanstack/query-broadcast-client-experimental 24.39% <ø> (ø)
@tanstack/query-codemods ∅ <ø> (∅)
@tanstack/query-core 97.45% <100.00%> (+0.04%) ⬆️
@tanstack/query-devtools 3.48% <ø> (ø)
@tanstack/query-persist-client-core 79.47% <ø> (ø)
@tanstack/query-sync-storage-persister 84.61% <ø> (ø)
@tanstack/query-test-utils ∅ <ø> (∅)
@tanstack/react-query 95.95% <ø> (ø)
@tanstack/react-query-devtools 10.00% <ø> (ø)
@tanstack/react-query-next-experimental ∅ <ø> (∅)
@tanstack/react-query-persist-client 100.00% <ø> (ø)
@tanstack/solid-query 78.13% <ø> (ø)
@tanstack/solid-query-devtools ∅ <ø> (∅)
@tanstack/solid-query-persist-client 100.00% <ø> (ø)
@tanstack/svelte-query 87.58% <ø> (ø)
@tanstack/svelte-query-devtools ∅ <ø> (∅)
@tanstack/svelte-query-persist-client 100.00% <ø> (ø)
@tanstack/vue-query 71.10% <ø> (ø)
@tanstack/vue-query-devtools ∅ <ø> (∅)
🚀 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.

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

🧹 Nitpick comments (1)
packages/query-core/src/utils.ts (1)

273-286: Micro-opt: hoist hasOwn and avoid double reads of b[key]

Hoist hasOwn and reuse bItem to shave a couple of lookups in tight loops.

Apply:

- let equalItems = 0
+ const hasOwn = Object.prototype.hasOwnProperty
+ let equalItems = 0
@@
- if (
- (array || Object.prototype.hasOwnProperty.call(a, key)) &&
+ if (
+ (array || hasOwn.call(a, key)) &&
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b998f68 and e6029db.

📒 Files selected for processing (1)
  • packages/query-core/src/utils.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/query-core/src/utils.ts (1)
packages/query-core/src/index.ts (1)
  • replaceEqualDeep (19-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Preview
  • GitHub Check: Test
🔇 Additional comments (3)
packages/query-core/src/utils.ts (3)

262-263: Confirm intent: bail out for non-plain arrays/objects

Early-returning b when neither a plain array nor a plain object skips structural sharing for sparse arrays, typed arrays, class instances, Dates, Maps/Sets, etc. Verify this matches prior behavior and expectations for consumers. If parity with previous semantics is desired, add tests around sparse arrays and typed arrays.


264-269: Prealloc and key-caching look good

Pre-allocating new Array(bSize) and caching key lists should reduce allocations and property lookups on hot paths.


292-292: Return condition reads clearly

Reusing a only when sizes match and all items are equal preserves structural sharing without false positives. LGTM.

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: 0

♻️ Duplicate comments (1)
packages/query-core/src/utils.ts (1)

271-283: Cache bItem to avoid repeated property lookups inside the hot loop.

Reads b[key] twice per iteration. Caching improves locality and aligns with the PR’s stated perf goals.

 for (let i = 0; i < bSize; i++) {
 const key = array ? i : bItems[i]
 const aItem = a[key]
+ const bItem = b[key]
 if (
- (array || Object.prototype.hasOwnProperty.call(a, key)) &&
- aItem === undefined &&
- b[key] === undefined
+ (array || Object.prototype.hasOwnProperty.call(a, key)) &&
+ aItem === undefined &&
+ bItem === undefined
 ) {
 copy[key] = undefined
 equalItems++
 } else {
- const value = replaceEqualDeep(aItem, b[key])
+ const value = replaceEqualDeep(aItem, bItem)
 copy[key] = value
 if (value === aItem && aItem !== undefined) {
 equalItems++
 }
 }
 }
🧹 Nitpick comments (1)
packages/query-core/src/utils.ts (1)

261-268: Early-return and pre-allocation look good; trim an unnecessary allocation.

aItems is only used to compute aSize. Avoid creating it to reduce work/memory.

- const aItems = array ? a : Object.keys(a)
- const aSize = aItems.length
+ const aSize = array ? a.length : Object.keys(a).length
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5e527f3 and 1007495.

📒 Files selected for processing (1)
  • packages/query-core/src/utils.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/query-core/src/utils.ts (1)
packages/query-core/src/index.ts (1)
  • replaceEqualDeep (19-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test
  • GitHub Check: Preview
🔇 Additional comments (1)
packages/query-core/src/utils.ts (1)

275-276: Prototype-safe hasOwnProperty: LGTM.

Switching to Object.prototype.hasOwnProperty.call(a, key) avoids issues when hasOwnProperty is shadowed.

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: 0

Caution

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

⚠️ Outside diff range comments (1)
packages/query-core/src/utils.ts (1)

373-402: Use safe own-check and correct prototype comment

  • Change the own-property check on prot to use the helper for safety:
    if (!hasOwn.call(prot, 'isPrototypeOf')) {
     return false
    }
  • Revise the comment before the getPrototypeOf guard to accurately state that we reject any object whose prototype isn’t exactly Object.prototype (null-proto objects are already accepted by the early ctor === undefined return).
♻️ Duplicate comments (1)
packages/query-core/src/utils.ts (1)

248-248: Good fix: prototype-safe own-property check and cached reads.

Resolved the earlier "shadowed hasOwnProperty" concern and reduced repeated property access by caching aItem/bItem. Looks solid.

Also applies to: 319-327

🧹 Nitpick comments (3)
packages/query-core/src/utils.ts (3)

255-256: Prefer unknown over any in the implementation signature.

Keeping the overload replaceEqualDeep<T>(a: unknown, b: T): T is great. For the implementation, returning unknown avoids leaking any while staying compatible with the overloads.

-export function replaceEqualDeep(a: unknown, b: unknown): any {
+export function replaceEqualDeep(a: unknown, b: unknown): unknown {

311-345: Object path: tight loop and O(1) own-checks LGTM.

  • for..in over b avoids materializing key arrays.
  • Equality counting gated by hasOwn.call(a, k) is correct.
  • Recursion preserves references where possible.

One note: symbol keys aren’t considered (consistent with JSON-only constraint). If that’s intentional, consider documenting it near replaceData to preempt surprises.


368-370: Sparse/augmented arrays won’t be treated as "plain arrays". Please confirm.

isPlainArray returns false for sparse arrays or arrays with extra enumerable props (length !== Object.keys(value).length). That changes behavior vs a naive Array.isArray check and will fall back to "return b" instead of structural sharing. If intentional, add tests for:

  • sparse arrays (holes)
  • arrays with extra enumerable props

I can draft these tests if desired.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1007495 and 3c69c31.

📒 Files selected for processing (1)
  • packages/query-core/src/utils.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test
🔇 Additional comments (2)
packages/query-core/src/utils.ts (2)

261-299: Array path perf refactor looks correct.

Pre-allocation + strict-equality fast path + recursive sharing are implemented correctly, and the equality accounting (i < aSize) handles length mismatches safely.


301-309: Type-mismatch early return preserves previous semantics.

Returning b when only one side is an array or a non-plain object matches the intended "JSON-only" structural sharing behavior. Good.

Comment on lines 301 to 309
// only 1 is an array
if (aIsArr || bIsArr) {
return b
}

// at least 1 is not an object
if (!isPlainObject(a) || !isPlainObject(b)) {
return b
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

could the "only 1 is an array" case not be removed because we would also go into the "at least 1 is not an object" case and also return b there?

all tests still pass if I just remove that check, and we could then also inline aIsArr and bIsArr because they are only used once then ...

Copy link
Contributor Author

@Sheraff Sheraff Sep 1, 2025

Choose a reason for hiding this comment

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

yeah it could, it's just less expensive since we already have the booleans, and isPlainObject does a lot

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: 0

Caution

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

⚠️ Outside diff range comments (2)
packages/query-core/src/utils.ts (2)

345-346: Don’t call a potentially shadowed hasOwnProperty on prototypes

prot.hasOwnProperty('isPrototypeOf') can throw if hasOwnProperty is overridden on that prototype. Use the prototype-safe helper.

Apply:

- if (!prot.hasOwnProperty('isPrototypeOf')) {
+ if (!hasOwn.call(prot, 'isPrototypeOf')) {

327-356: Allow null-prototype objects in isPlainObject
Relax the final prototype check so that Object.getPrototypeOf(o) === null is treated as plain (e.g. change

if (Object.getPrototypeOf(o) !== Object.prototype) {
 return false
}

to something like

const proto = Object.getPrototypeOf(o)
if (proto !== Object.prototype && proto !== null) {
 return false
}

) to restore the existing test behavior in utils.test.tsx.

♻️ Duplicate comments (1)
packages/query-core/src/utils.ts (1)

248-248: Prototype-safe own-property helper: LGTM

Using a cached reference and calling via .call avoids shadowing risks. This addresses the earlier review concern.

🧹 Nitpick comments (1)
packages/query-core/src/utils.ts (1)

322-324: Clarify dense-array intent in isPlainArray

Minor: add a short doc comment noting that sparse arrays or arrays with extra enumerable props return false.

+/** True only for dense Arrays with no extra enumerable properties (sparse arrays excluded). */
 export function isPlainArray(value: unknown): value is Array<unknown> {
 return Array.isArray(value) && value.length === Object.keys(value).length
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3c69c31 and 91494ca.

📒 Files selected for processing (1)
  • packages/query-core/src/utils.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/query-core/src/utils.ts (1)
packages/query-core/src/index.ts (1)
  • replaceEqualDeep (19-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test
  • GitHub Check: Preview
🔇 Additional comments (1)
packages/query-core/src/utils.ts (1)

263-300: replaceEqualDeep hot path and allocation strategy: LGTM

Early bailout + preallocated arrays + cached aItem/bItem lookups are clean and align with the perf goals. The equality accounting also correctly preserves a only when sizes match and all items are equal.

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

@TkDodo TkDodo TkDodo left review comments

@coderabbitai coderabbitai[bot] coderabbitai[bot] left review comments

Assignees
No one assigned
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

2 participants

AltStyle によって変換されたページ (->オリジナル) /