Skip to content

PoC Migrating from React.ComponentType to React.ReactElement - #4431

Draft
Loloekk wants to merge 6 commits into
mainfrom
@Loloekk/PoC-migrate-change-original-source
Draft

PoC Migrating from React.ComponentType to React.ReactElement#4431
Loloekk wants to merge 6 commits into
mainfrom
@Loloekk/PoC-migrate-change-original-source

Conversation

@Loloekk

@Loloekk Loloekk commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Description

Changes

Before & after - visual documentation

Test plan

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

@Loloekk
Loloekk force-pushed the @Loloekk/PoC-migrate-change-original-source branch from 749de62 to 2492c9a Compare July 30, 2026 13:46
@Loloekk
Loloekk requested a review from Copilot July 31, 2026 05:53

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 updates the example app’s custom StackContainer/TabsContainer route-config model to pass prebuilt React elements (instead of component types), and adds several PoC test screens + a documented “simple stack navigation” scenario under apps/src/tests/PoC.

Changes:

  • Switched stack/tabs route configs from Component: React.ComponentType to element: React.ReactElement and updated container rendering/mapping accordingly.
  • Added PoC screens (TestStackPoC, TestTabsPoC) and a new documented scenario (test-stack-simple-navPoC).
  • Updated the example app test surface (issue-test exports) and TypeScript config for apps/.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
apps/tsconfig.json Excludes src/tests/** from the apps TS project.
apps/src/tests/PoC/TestTabsPoC.tsx New PoC screen for tabs container behavior with shared vs inline elements.
apps/src/tests/PoC/TestStackPoC.tsx New PoC screen for stack container behavior with shared vs inline elements.
apps/src/tests/PoC/test-stack-simple-navPoC/scenario.md New written scenario for validating stack push/pop and gestures.
apps/src/tests/PoC/test-stack-simple-navPoC/scenario-description.ts Scenario metadata for the new “simple stack navigation” scenario.
apps/src/tests/PoC/test-stack-simple-navPoC/index.tsx Scenario implementation using StackContainer + shared test components.
apps/src/tests/PoC/index.ts Barrel exports for PoC scenarios.
apps/src/tests/issue-tests/TestPoC.tsx New issue-test PoC screen demonstrating context/provider behavior per “slot”.
apps/src/tests/issue-tests/index.ts Comments out most issue-test exports; leaves only TestPoC exported.
apps/src/shared/containers/tabs/TabsContainerItem.types.ts Updates item prop from Component to element.
apps/src/shared/containers/tabs/TabsContainerItem.tsx Renders element and wraps in SafeAreaView when needed.
apps/src/shared/containers/tabs/TabsContainer.types.tsx Changes tab route config shape to use element.
apps/src/shared/containers/tabs/TabsContainer.tsx Resolves route content via useElementsByName and passes element to items.
apps/src/shared/containers/tabs/reducer.tsx Adjusts config-to-route conversion to omit element.
apps/src/shared/containers/stack/StackContainer.types.ts Changes stack route config shape to use element.
apps/src/shared/containers/stack/StackContainer.tsx Resolves route content via useElementsByName and renders element.
apps/src/shared/containers/stack/reducer.tsx Adjusts config-to-route conversion to omit element.
apps/src/shared/containers/shared/use-elements-by-name.ts Renames/migrates mapping hook to return elements by route name.
Suppressed comments (2)

apps/src/shared/containers/shared/use-elements-by-name.ts:13

  • useElementsByName currently only reads config.element. There are still many route configs in the app tests that use the legacy Component field (e.g. apps/src/tests/single-feature-tests/tabs/test-tabs-simple-nav/index.tsx:51-65 and apps/src/tests/component-integration-tests/scroll-view-marker/test-stack-svm-lift-on-scroll/index.tsx:19-35). With the new container implementation, those scenarios will hit the "No config matches" error at runtime because the map value becomes undefined. Consider supporting legacy Component by creating an element when element isn’t provided (or migrate all callers in this PR).
    apps/src/shared/containers/tabs/TabsContainerItem.tsx:60
  • safeAreaConfigurationWithDefault is computed (and used to decide whether to wrap in SafeAreaView), but it isn’t actually passed to SafeAreaView. This means the intended default edges (e.g. { bottom: true } on Android) are ignored.
  const safeAreaConfigurationWithDefault = getSafeAreaViewEdges(
    safeAreaConfiguration?.edges,
  );

  const anySAVEdgeSet = Object.values(safeAreaConfigurationWithDefault).some(

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

Comment on lines +100 to +102
{/* Clone so multiple stack entries of the same route get distinct instances.
{React.cloneElement(element)} */}
{element}
Comment on lines +1 to +4
// // @ts-nocheck

export { default as Test42 } from './Test42'; // [E2E skipped]: can't check orientation, unclear problem description
export { default as Test111 } from './Test111'; // [E2E skipped]: can't check flickering
export { default as Test263 } from './Test263'; // [E2E skipped]: example differs from PR, even if changed the problem still occurs
export { default as Test349 } from './Test349'; // [E2E skipped]: can't check autofill easily, wrong prop name
export { default as Test364 } from './Test364'; // [E2E skipped]: tabBarVisible prop doesn't exist anymore, suggested solution is to change navigator hierarchy (proposed in PR and in react-navigation docs)
export { default as Test432 } from './Test432'; // [E2E created]
export { default as Test528 } from './Test528'; // [E2E created](iOS): Detox supports changing orientation only on iOS
export { default as Test550 } from './Test550'; // [E2E skipped]: the prop does not work, when fixed we can add the test
export { default as Test556 } from './Test556'; // [E2E skipped]: can't check flickering nor non-deterministic white screen bug
export { default as Test564 } from './Test564'; // [E2E skipped]: issue still present
export { default as Test577 } from './Test577'; // [E2E created](iOS): issue is related to iOS modal
export { default as Test593 } from './Test593'; // [E2E created]
export { default as Test619 } from './Test619'; // [E2E skipped]: can't check components jumping
export { default as Test624 } from './Test624'; // [E2E skipped]: PR changed library internals, test screen seems unrelated
export { default as Test640 } from './Test640'; // [E2E created]
export { default as Test642 } from './Test642'; // [E2E skipped]: can't check status bar visibility/style
export { default as Test645 } from './Test645'; // [E2E created](iOS): headerLargeTitle is supported only on iOS
export { default as Test648 } from './Test648'; // [E2E skipped]: can't check animation in a meaningful way
export { default as Test649 } from './Test649'; // [E2E created](iOS): headerLargeTitle is supported only on iOS
export { default as Test654 } from './Test654'; // [E2E created](iOS): issue related to iOS native back button
export { default as Test658 } from './Test658'; // [E2E created]
export { default as Test662 } from './Test662'; // [E2E skipped]: can't check animation in a meaningful way
export { default as Test691 } from './Test691'; // [E2E created](iOS): issue related to iOS modal behavior
export { default as Test702 } from './Test702'; // [E2E skipped]: can't check animation in a meaningful way
export { default as Test706 } from './Test706'; // [E2E skipped]: can't check font weight
export { default as Test726 } from './Test726'; // [E2E created](iOS): issue related to iOS
export { default as Test748 } from './Test748'; // [E2E skipped]: issue unclear, Test432 covers more complex cases already
export { default as Test750 } from './Test750'; // [E2E skipped]: can't check insets
export { default as Test758 } from './Test758'; // [E2E created](iOS): PR related to iOS search bar
export { default as Test761 } from './Test761'; // [E2E skipped]: can't check animation in a meaningful way
export { default as Test779 } from './Test779'; // [E2E skipped]: can't check animation in a meaningful way
export { default as Test780 } from './Test780'; // [E2E skipped]: can't use native swipe back gesture
export { default as Test791 } from './Test791'; // [E2E created](iOS): issue related to iOS
export { default as Test800 } from './Test800';
export { default as Test817 } from './Test817';
export { default as Test830 } from './Test830';
export { default as Test831 } from './Test831';
export { default as Test844 } from './Test844';
export { default as Test852 } from './Test852';
export { default as Test860 } from './Test860';
export { default as Test861 } from './Test861';
export { default as Test865 } from './Test865';
export { default as Test881 } from './Test881';
export { default as Test887 } from './Test887';
export { default as Test913 } from './Test913';
export { default as Test999 } from './Test999';
export { default as Test1017 } from './Test1017';
export { default as Test1031 } from './Test1031';
export { default as Test1032 } from './Test1032';
export { default as Test1036 } from './Test1036';
export { default as Test1072 } from './Test1072';
export { default as Test1084 } from './Test1084';
export { default as Test1091 } from './Test1091';
export { default as Test1096 } from './Test1096';
export { default as Test1097 } from './Test1097';
export { default as Test1153 } from './Test1153';
export { default as Test1157 } from './Test1157';
export { default as Test1162 } from './Test1162';
export { default as Test1166 } from './Test1166';
export { default as Test1188 } from './Test1188';
export { default as Test1190 } from './Test1190';
export { default as TestFreeze } from './TestFreeze';
export { default as Test1198 } from './Test1198';
export { default as Test1204 } from './Test1204';
export { default as Test1209 } from './Test1209';
export { default as Test1213 } from './Test1213';
export { default as Test1214 } from './Test1214';
export { default as Test1227 } from './Test1227';
export { default as Test1228 } from './Test1228';
export { default as Test1259 } from './Test1259';
export { default as Test1260 } from './Test1260';
export { default as Test1296 } from './Test1296';
export { default as Test1299 } from './Test1299';
export { default as Test1391 } from './Test1391';
export { default as Test1419 } from './Test1419';
export { default as Test1463 } from './Test1463';
export { default as Test1473 } from './Test1473';
export { default as Test1476 } from './Test1476';
export { default as Test1509 } from './Test1509';
export { default as Test1539 } from './Test1539';
export { default as Test1645 } from './Test1645';
export { default as Test1646 } from './Test1646';
// export { default as Test1649 } from './Test1649';
export { default as Test1671 } from './Test1671';
export { default as Test1683 } from './Test1683';
export { default as Test1726 } from './Test1726';
export { default as Test1791 } from './Test1791';
export { default as Test1802 } from './Test1802';
export { default as Test1829 } from './Test1829';
export { default as Test1844 } from './Test1844';
export { default as Test1864 } from './Test1864';
export { default as Test1970 } from './Test1970';
export { default as Test1975 } from './Test1975';
export { default as Test1981 } from './Test1981';
export { default as Test2002 } from './Test2002';
export { default as Test2008 } from './Test2008';
export { default as Test2028 } from './Test2028';
export { default as Test2048 } from './Test2048';
export { default as Test2069 } from './Test2069';
export { default as Test2118 } from './Test2118';
export { default as Test2125 } from './Test2125'; // [E2E skipped]: issue happens nondeterministically
export { default as Test2167 } from './Test2167';
export { default as Test2175 } from './Test2175';
export { default as Test2184 } from './Test2184';
export { default as Test2223 } from './Test2223';
export { default as Test2227 } from './Test2227';
export { default as Test2229 } from './Test2229';
export { default as Test2232 } from './Test2232';
export { default as Test2235 } from './Test2235';
export { default as Test2252 } from './Test2252';
export { default as Test2271 } from './Test2271';
export { default as Test2282 } from './Test2282';
export { default as Test2317 } from './Test2317';
export { default as Test2320 } from './Test2320';
export { default as Test2332 } from './Test2332';
export { default as Test2379 } from './Test2379';
export { default as Test2395 } from './Test2395';
export { default as Test2466 } from './Test2466';
export { default as Test2522 } from './Test2522';
export { default as Test2538 } from './Test2538';
export { default as Test2543 } from './Test2543'; // [E2E created](iOS): issue related to iOS formSheet initial detent
export { default as Test2552 } from './Test2552';
export { default as Test2559 } from './Test2559';
export { default as Test2560 } from './Test2560';
export { default as Test2611 } from './Test2611';
export { default as Test2631 } from './Test2631';
export { default as Test2668 } from './Test2668';
export { default as Test2675 } from './Test2675';
export { default as Test2714 } from './Test2714';
export { default as Test2717 } from './Test2717';
export { default as Test2767 } from './Test2767';
export { default as Test2789 } from './Test2789';
export { default as Test2809 } from './Test2809';
export { default as Test2811 } from './Test2811';
export { default as Test2819 } from './Test2819';
export { default as Test2842 } from './Test2842'; // [E2E created](iOS): issue is related to iOS
export { default as Test2855 } from './Test2855';
export { default as Test2877 } from './Test2877'; // [E2E created](iOS): issue is related to formSheet on iOS
export { default as Test2895 } from './Test2895';
export { default as Test2899 } from './Test2899';
export { default as Test2933 } from './Test2933';
export { default as Test2926 } from './Test2926'; // [E2E created](iOS): PR related to iOS search bar
export { default as Test2963 } from './Test2963'; // [E2E created](iOS): issue related to iOS
export { default as Test3004 } from './Test3004';
export { default as Test3006 } from './Test3006';
export { default as Test3045 } from './Test3045';
export { default as Test3074 } from './Test3074';
export { default as Test3093 } from './Test3093';
export { default as Test3111 } from './Test3111';
export { default as Test3168 } from './Test3168';
export { default as Test3173 } from './Test3173';
export { default as Test3212 } from './Test3212';
export { default as Test3236 } from './Test3236';
export { default as Test3239 } from './Test3239';
export { default as Test3248 } from './Test3248';
export { default as Test3265 } from './Test3265';
export { default as Test3271 } from './Test3271';
export { default as Test3282 } from './Test3282';
export { default as Test3288 } from './Test3288';
export { default as Test3336 } from './Test3336';
export { default as Test3342 } from './Test3342';
export { default as Test3345 } from './Test3345';
export { default as Test3346 } from './Test3346';
export { default as Test3369 } from './Test3369';
export { default as Test3379 } from './Test3379';
export { default as Test3422 } from './Test3422';
export { default as Test3425 } from './Test3425';
export { default as Test3443 } from './Test3443';
export { default as Test3446 } from './Test3446';
export { default as Test3450 } from './Test3450';
export { default as Test3480 } from './Test3480';
export { default as Test3492 } from './Test3492';
export { default as Test3521 } from './Test3521';
export { default as Test3522 } from './Test3522';
export { default as Test3564 } from './Test3564';
export { default as Test3566 } from './Test3566';
export { default as Test3568 } from './Test3568';
export { default as Test3576 } from './Test3576';
export { default as Test3596 } from './Test3596';
export { default as Test3606 } from './Test3606';
export { default as Test3611 } from './Test3611';
export { default as Test3617 } from './Test3617';
export { default as Test3636 } from './Test3636';
export { default as Test3760 } from './Test3760';
export { default as Test3770 } from './Test3770';
export { default as Test3793 } from './Test3793';
export { default as Test3816 } from './Test3816';
export { default as Test3833 } from './Test3833';
export { default as Test3835 } from './Test3835';
export { default as Test3867 } from './Test3867';
export { default as Test3885 } from './Test3885';
export { default as Test3910 } from './Test3910';
export { default as Test4027 } from './Test4027';
export { default as Test4064 } from './Test4064';
export { default as Test4090 } from './Test4090';
export { default as Test4155 } from './Test4155';
export { default as Test4161 } from './Test4161';
export { default as Test4220 } from './Test4220';
export { default as Test4240 } from './Test4240';
export { default as Test4244 } from './Test4244';
export { default as Test4258 } from './Test4258';
export { default as Test4264 } from './Test4264';
export { default as Test4265 } from './Test4265';
export { default as Test4276 } from './Test4276';
export { default as Test4351 } from './Test4351';
export { default as Test4357 } from './Test4357';
export { default as Test4361 } from './Test4361';
export { default as TestScreenAnimation } from './TestScreenAnimation';
// The following test was meant to demo the "go back" gesture using Reanimated
// but the associated PR in react-navigation is currently put on hold
// export { default as TestScreenAnimationV5 } from './TestScreenAnimationV5';
export { default as TestHeader } from './TestHeader';
export { default as TestPreload } from './TestPreload';
export { default as TestActivityStateProgression } from './TestActivityStateProgression';
export { default as TestHeaderTitle } from './TestHeaderTitle';
export { default as TestHeaderHeight } from './TestHeaderHeight';
export { default as TestModalNavigation } from './TestModalNavigation';
export { default as TestMemoryLeak } from './TestMemoryLeak';
export { default as TestFormSheet } from './TestFormSheet';
export { default as TestAndroidTransitions } from './TestAndroidTransitions';
export { default as TestAnimation } from './TestAnimation';
export { default as TestBottomTabs } from './TestBottomTabs';
export { default as TestBottomTabsOrientation } from './TestBottomTabsOrientation';
export { default as TestScreenStack } from './TestScreenStack';
export { default as TestSplit } from './TestSplit';
export { default as TestSafeAreaViewIOS } from './TestSafeAreaViewIOS';
export { default as TestStackNesting } from './TestStackNesting';
export { default as TestScreenFooterKeyboardInsets } from './TestScreenFooterKeyboardInsets';
// export { default as Test42 } from './Test42'; // [E2E skipped]: can't check orientation, unclear problem description
// export { default as Test111 } from './Test111'; // [E2E skipped]: can't check flickering
@Loloekk
Loloekk force-pushed the @Loloekk/PoC-migrate-change-original-source branch from cc71840 to 470ceb9 Compare August 4, 2026 06:53
@Loloekk Loloekk changed the title @loloekk/po c migrate change original source PoC Migrating from React.ComponentType to React.ReactElement Aug 4, 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.

2 participants