Skip to content

feat(iOS, Stack v5): Refactor Stack Header implementation and handle selective updates#4248

Open
kmichalikk wants to merge 6 commits into
mainfrom
@kmichalikk/header-items-decouple
Open

feat(iOS, Stack v5): Refactor Stack Header implementation and handle selective updates#4248
kmichalikk wants to merge 6 commits into
mainfrom
@kmichalikk/header-items-decouple

Conversation

@kmichalikk

@kmichalikk kmichalikk commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Closes https://github.com/software-mansion/react-native-screens-labs/issues/1567

Description

This PR decouples React component views from native UIKit logic and introduces selective item updates so only the changed item rebuilds.

Changes

  • removed menu state tracker from ComponentView
  • removed RNSStackHeaderData data class, now props are read directly from ComponentView via protocol
  • merged RNSStackHeaderItemCoordinator into RNSStackHeaderCoordinator and removed the class
  • added selective rebuilds with itemId
  • split menu rebuild from item rebuild; if only menu changes, item doesn't get rebuilt
  • when menu or item definition changes, the state for menu is cleared and reset to defaults - this is by design to match android
  • added SFT for visually inspecting the updates
  • unfortunately, I was unable to make the coordinator stateless because it needs to hold references to header items and state trackers for rebuilding (bar items in UIKit are immutable)

Before & after - visual documentation

Before After
no-selective-updates.mov
selective-updates.mov

Test plan

Use test-stack-header-selective-updates-ios.

Checklist

  • Included code example that can be used to test this change.
  • For visual changes, included screenshots / GIFs / recordings documenting the change.
  • For API changes, updated relevant public types.
  • Ensured that CI passes

@kmichalikk kmichalikk self-assigned this Jul 2, 2026
std::shared_ptr<const react::RNSStackHeaderConfigShadowNode::ConcreteState> _state;
RNSStackHeaderConfigShadowStateProxy *_Nonnull _shadowStateProxy;
RNSStackHeaderConfigEventEmitter *_Nonnull _reactEventEmitter;
NSMutableArray<id> *_children;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

the protocol defines because I don't want to leak react views here & only need to handle 2 data providing protocols for items and spacers

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the iOS (gamma / Stack v5) header implementation to decouple native UIKit updates from React component views, and introduces selective updates so only the affected header item (or only its menu) is rebuilt.

Changes:

  • Replaces the previous “build RNSStackHeaderData then apply” flow with a coordinator that reads config + children directly via RNSStackHeaderConfigDataProviding.
  • Adds selective update entry points (rebuildItemWithId, reapplyMenuForItemWithId) and a menu tracker registry to preserve menu toggle state across interactions.
  • Adds a new Single Feature Test scenario for visually validating selective updates on iOS.

Reviewed changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
ios/gamma/stack/screen/RNSStackScreenHeaderCoordinator.mm New coordinator-driven rebuild + selective item/menu update logic; new menu tracker registry integration.
ios/gamma/stack/screen/RNSStackScreenHeaderCoordinator.h Exposes coordinator API and provider/delegate wiring (config, frame changes, events).
ios/gamma/stack/screen/RNSStackScreenComponentView.h Removes dependency on RNSStackHeaderData.
ios/gamma/stack/screen/RNSStackNavigationItemCoordinator.mm Deleted (logic moved into header coordinator).
ios/gamma/stack/screen/RNSStackNavigationItemCoordinator.h Deleted (logic moved into header coordinator).
ios/gamma/stack/host/RNSStackNavigationBarCoordinator.mm Simplifies API to setHidden:animated:.
ios/gamma/stack/host/RNSStackNavigationBarCoordinator.h Header update for the simplified navigation bar API.
ios/gamma/stack/header/RNSStackHeaderMenuTrackerRegistry.mm New registry storing per-item toggle state trackers.
ios/gamma/stack/header/RNSStackHeaderMenuTrackerRegistry.h Header for the new tracker registry.
ios/gamma/stack/header/RNSStackHeaderMenuCoordinator.mm Adds menuToggleCallback so callers can reapply menus after toggle interactions.
ios/gamma/stack/header/RNSStackHeaderMenuCoordinator.h Documents and exposes the new menuToggleCallback API.
ios/gamma/stack/header/RNSStackHeaderItemSpacerComponentView.mm Updates invalidation callback name for spacer changes.
ios/gamma/stack/header/RNSStackHeaderItemInvalidationDelegate.h Splits invalidation into item rebuild vs menu-only update vs spacer rebuild.
ios/gamma/stack/header/RNSStackHeaderItemDataProviding.h Removes menu toggle tracker from the item-providing protocol (now coordinator-managed).
ios/gamma/stack/header/RNSStackHeaderItemComponentView.mm Emits selective invalidations (rebuild item vs menu-only change).
ios/gamma/stack/header/RNSStackHeaderItemComponentView.h Adds RNSViewFrameChangeDelegate conformance; updates exposed surface.
ios/gamma/stack/header/RNSStackHeaderData.mm Deleted (no longer used).
ios/gamma/stack/header/RNSStackHeaderData.h Deleted (no longer used).
ios/gamma/stack/header/RNSStackHeaderContentFactory.mm Stops applying menus inside the factory; returns base bar button item only.
ios/gamma/stack/header/RNSStackHeaderContentFactory.h Updates docs to reflect menu application moving out of the factory.
ios/gamma/stack/header/RNSStackHeaderConfigDataProviding.h New protocol for exposing config + children to the coordinator.
ios/gamma/stack/header/RNSStackHeaderConfigComponentView.mm Wires provider/delegates into coordinator; routes invalidations to selective coordinator APIs.
ios/gamma/stack/header/RNSStackHeaderConfigComponentView.h Declares protocol conformances and exposes config properties + children.
apps/src/tests/single-feature-tests/stack-v5/test-stack-header-selective-updates-ios/scenario.md New manual test scenario steps for selective updates validation.
apps/src/tests/single-feature-tests/stack-v5/test-stack-header-selective-updates-ios/scenario-description.ts Scenario metadata for the new SFT.
apps/src/tests/single-feature-tests/stack-v5/test-stack-header-selective-updates-ios/index.tsx New SFT implementation exercising selective updates and menu behaviors.
apps/src/tests/single-feature-tests/stack-v5/index.ts Registers the new SFT in the stack-v5 scenario list.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +45 to +49
[_leadingBarButtonItems removeAllObjects];
[_trailingBarButtonItems removeAllObjects];
[_barButtonItemsByItemId removeAllObjects];
[_trackerRegistry clear];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is so iOS implementation works the same as android implementation

Comment thread ios/gamma/stack/screen/RNSStackScreenHeaderCoordinator.mm
Comment thread ios/gamma/stack/screen/RNSStackScreenHeaderCoordinator.mm
Comment thread ios/gamma/stack/header/RNSStackHeaderItemComponentView.mm Outdated
Comment thread ios/gamma/stack/header/RNSStackHeaderItemInvalidationDelegate.h
Comment thread ios/gamma/stack/screen/RNSStackScreenHeaderCoordinator.h Outdated
Comment thread ios/gamma/stack/header/RNSStackHeaderConfigComponentView.mm
@kmichalikk kmichalikk force-pushed the @kmichalikk/header-items-decouple branch from 42d3af0 to c7b33f7 Compare July 2, 2026 12:00
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.

2 participants