From df39ceac6db6511518aed4766e6a59aa24fb53ec Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Thu, 12 Sep 2024 10:35:30 -0700 Subject: [PATCH] fix(react, vue): add default value for navManager on tabs (#29865) Issue number: N/A --------- ## What is the current behavior? React: Refreshes the app upon a tab button press and returns to the first tab content. Vue: Does not render the tabs when the app doesn't use a router at all because of `ionRouter` not being defined. ## What is the new behavior? - React: Users can press on the tab button without having the app refresh and displays the associated tab content. - Vue: Renders the tabs when router is not present. ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information Dev build: 8.3.1-dev.11726094383.1cdbab6f How to test: I recommend using the playgrounds in the Ionic Framework docs repo since those playgrounds are setup to not have any routers at a high level. 1. Navigate to the [basic usage section](https://ionic-docs-git-rou-11138-ionic1.vercel.app/docs/api/tabs#basic-usage) 2. Select React 3. Open the StackBlitz example 4. Click on any tab button 5. Notice that the app refreshes and returns to the first tab content 6. Install the dev build: `npm install @ionic/react@8.3.1-dev.11726094383.1cdbab6f` 7. Verify that the app doesn't refresh and reset the content after clicking on any tab button 8. Navigate to the [basic usage section](https://ionic-docs-git-rou-11138-ionic1.vercel.app/docs/api/tabs#basic-usage) 9. Select Vue 10. Open the StackBlitz example 11. Notice that tabs doesn't render 12. Open the console and notice that there's an error `ionRouter is undefined` 13. Install the dev build: `npm install @ionic/vue@8.3.1-dev.11726094383.1cdbab6f` 14. Verify that it renders 15. Verify that the console no longer shows the error --- .../src/components/navigation/IonTabBar.tsx | 6 +++-- packages/vue/src/components/IonTabBar.ts | 23 +++++++++++-------- packages/vue/src/components/IonTabButton.ts | 14 ++++++----- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/packages/react/src/components/navigation/IonTabBar.tsx b/packages/react/src/components/navigation/IonTabBar.tsx index 7ae5c9e7cd..f1a66440fc 100644 --- a/packages/react/src/components/navigation/IonTabBar.tsx +++ b/packages/react/src/components/navigation/IonTabBar.tsx @@ -212,8 +212,10 @@ class IonTabBarUnwrapped extends React.PureComponent { const href = tabs[key].originalHref; - return currentRoute.pathname.startsWith(href); + return currentRoute?.pathname.startsWith(href); }); /** @@ -170,17 +170,20 @@ export const IonTabBar = defineComponent({ * If we went to tab2 then back to tab1, we should * land on /tabs/tab1/child instead of /tabs/tab1. */ - if (activeTab !== prevActiveTab || prevHref !== currentRoute.pathname) { + if ( + activeTab !== prevActiveTab || + prevHref !== currentRoute?.pathname + ) { /** * By default the search is `undefined` in Ionic Vue, * but Vue Router can set the search to the empty string. * We check for truthy here because empty string is falsy * and currentRoute.search cannot ever be a boolean. */ - const search = currentRoute.search ? `?${currentRoute.search}` : ""; + const search = currentRoute?.search ? `?${currentRoute.search}` : ""; tabs[activeTab] = { ...tabs[activeTab], - currentHref: currentRoute.pathname + search, + currentHref: currentRoute?.pathname + search, }; } @@ -189,7 +192,7 @@ export const IonTabBar = defineComponent({ * set the previous tab back to its original href. */ if ( - currentRoute.routerAction === "pop" && + currentRoute?.routerAction === "pop" && activeTab !== prevActiveTab ) { tabs[prevActiveTab] = { @@ -226,7 +229,7 @@ export const IonTabBar = defineComponent({ if (activeChild) { tabDidChange && this.$props._tabsWillChange(activeTab); - if (hasRouterOutlet && ionRouter) { + if (hasRouterOutlet && ionRouter !== null) { ionRouter.handleSetCurrentTab(activeTab); } @@ -246,11 +249,11 @@ export const IonTabBar = defineComponent({ }, }, mounted() { - const ionRouter: any = inject("navManager"); + const ionRouter: any = inject("navManager", null); this.setupTabState(ionRouter); - ionRouter.registerHistoryChangeListener(() => + ionRouter?.registerHistoryChangeListener(() => this.checkActiveTab(ionRouter) ); }, diff --git a/packages/vue/src/components/IonTabButton.ts b/packages/vue/src/components/IonTabButton.ts index b5105a125a..b110a6209e 100644 --- a/packages/vue/src/components/IonTabButton.ts +++ b/packages/vue/src/components/IonTabButton.ts @@ -27,7 +27,7 @@ export const IonTabButton = /*@__PURE__*/ defineComponent({ defineCustomElement(); // TODO(FW-2969): type - const ionRouter: any = inject("navManager"); + const ionRouter: any = inject("navManager", null); const onClick = (ev: Event) => { if (ev.cancelable) { ev.preventDefault(); @@ -72,12 +72,14 @@ export const IonTabButton = /*@__PURE__*/ defineComponent({ * should direct users back to the root * of the tab. */ - if (prevActiveTab === tab) { - if (originalHref !== currentHref) { - ionRouter.resetTab(tab); + if (ionRouter !== null) { + if (prevActiveTab === tab) { + if (originalHref !== currentHref) { + ionRouter.resetTab(tab); + } + } else { + ionRouter.changeTab(tab, currentHref); } - } else { - ionRouter.changeTab(tab, currentHref); } }; return () => {