fix(query-core): re-attach MutationObserver to its in-flight mutation on resubscribe - #11217
fix(query-core): re-attach MutationObserver to its in-flight mutation on resubscribe#11217iamshahid1997 wants to merge 1 commit into
Conversation
… on resubscribe When the last listener unsubscribes, onUnsubscribe() removes the observer from its current mutation, but resubscribing never added it back. If React tore down and re-established the subscription while a mutation was in flight (StrictMode, <Activity> hide/show, re-suspending boundaries), the mutation settled against an empty observer list and the observer kept serving its frozen 'pending' snapshot forever. Mirror QueryObserver.onSubscribe(): when the first listener subscribes, re-attach to the current mutation and refresh the result in case the mutation settled while detached. Fixes TanStack#11171
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan includes up to 10 reviews per rolling hour; 9 remain after this review. 📝 WalkthroughWalkthroughMutationObserver now reattaches to its current mutation and refreshes its result after resubscription. Tests cover mutations completing during and after unsubscribed periods. ChangesMutation observer recovery
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to This localized change re-attaches mutation observation across subscription resubscription and adds regression coverage; no actionable merge-blocking risk remains beyond normal checks and review. Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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 |
|
duplicate of #11172 |
Fixes #11171
Problem
When the last listener unsubscribes,
MutationObserver.onUnsubscribe()removes the observer from its current mutation — but resubscribing never adds it back. React legitimately tears down and re-establishes the store subscription of a mounted component that keeps its state (<Activity mode="hidden">, re-suspending<Suspense>boundaries, StrictMode in dev).If that happens while a mutation is in flight, the mutation settles against an empty observer list, and the observer keeps serving its frozen
pendingsnapshot fromgetCurrentResult()forever:isPendingstaystrue→ submit buttons usingdisabled={isPending}stay disabled until remountmutate(vars, { onSuccess })never fireMutationCacheshowsuccesswhile the hook showspendingFix
Mirror
QueryObserver.onSubscribe(): when the first listener subscribes, re-attach the observer to its current mutation (Mutation.addObserveris already idempotent) and refresh the result snapshot in case the mutation settled while detached.Tests
Two regression tests in
mutationObserver.test.tsx, drivingsubscribe/unsubscribethe wayuseSyncExternalStoredoes:successand notifies the new listenerBoth fail on
mainand pass with the fix. Fullquery-core(627) andreact-query(577) suites pass.Summary by CodeRabbit
Bug Fixes
Tests