Fix tabs not updating stateful child components on tab switch#6458
Open
Fix tabs not updating stateful child components on tab switch#6458
Conversation
When switching tabs, SwiftUI reuses LoadedTabComponentView at the same structural position, preserving @State from the previous tab's children (e.g. Carousel page data, scroll index). Adding .id(selectedTabId) forces a full view recreation on each tab switch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
|
What might explain the Kaitlin being able to edit the and figma importer: |
MonikaMateska
approved these changes
Mar 13, 2026
Member
MonikaMateska
left a comment
There was a problem hiding this comment.
The fix looks good!
Might be worth a follow-up at some point: if we key ComponentsView’s ForEach by a stable component id (instead of index) and have stateful bits like the Carousel re-set when their input changes, we’d fix this at the source and not rely on the parent nuking the subtree, just a thought for later.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes an issue where switching tabs did not update content for stateful child components (e.g. Carousel showing stale pages/scroll position from the previously selected tab).
Root Cause
LoadedTabsComponentViewrenders a singleLoadedTabComponentViewat a fixed structural position in the SwiftUI view hierarchy. When the selected tab changes, SwiftUI sees the same view type at the same position and reuses it — preserving all@Statefrom the previous tab's child components.This is compounded by
ComponentsViewusingForEach(..., id: \.offset), which keys children by array index rather than component identity. A Carousel at index 1 in Tab A is treated as the same view as a Carousel at index 1 in Tab B, so its@State(data,index,carouselHeight,autoTimer) survives the tab switch. SincesetupData()only runs in.onAppear— which doesn't re-fire for a structurally reused view — the carousel renders stale page data.Fix
Add
.id(selectedTabId)toLoadedTabComponentView. This forces SwiftUI to destroy and recreate the entire tab content subtree when the selected tab changes, ensuring all child@Stateis freshly initialized.Alternatives Considered
Fix
ComponentsViewForEach identity — Use stable component IDs (every component has anidfield from the data model) instead ofid: \.offset. This would be a more surgical fix but has broader blast radius sinceComponentsView/FlexVStack/FlexHStackare used everywhere, and changing ForEach identity can affect animation behavior and performance across all component rendering.React to tab changes inside
CarouselView— Add.onChange(of: pages)or similar to re-runsetupData()when the carousel's input data changes. This only fixes the Carousel specifically and would need to be repeated for every stateful component that could appear inside tabs.Default carousel
sizetowidth: .fill— ChangeCarouselComponentViewModelto default nil size to(width: .fill, height: .fit)instead of(width: .fit, height: .fit). This was observed to mask the issue (likely by triggering enough layout invalidation to cause re-rendering) but doesn't address the underlying view identity problem.🤖 Generated with Claude Code
Note
Low Risk
Low risk, single-view identity change in SwiftUI; main impact is resetting child
@State(and potentially animations/scroll position) when switching tabs.Overview
Fixes stale state when switching tabs by forcing SwiftUI to rebuild the active tab subtree.
LoadedTabComponentViewis now keyed with.id(selectedTabId), so stateful child components are recreated on tab changes instead of reusing prior tab state.Written by Cursor Bugbot for commit a80274f. This will update automatically on new commits. Configure here.