mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-15 01:03:03 +08:00
fix(react, vue): add default value for navManager on tabs (#29865)
Issue number: N/A --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> 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? <!-- Please describe the behavior or changes that are being added by this PR. --> - 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 <!-- If this introduces a breaking change: 1. Describe the impact and migration path for existing applications below. 2. Update the BREAKING.md file with the breaking change. 3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer for more information. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> 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
This commit is contained in:
@ -212,8 +212,10 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
|
||||
if (this.props.onIonTabsDidChange) {
|
||||
this.props.onIonTabsDidChange(new CustomEvent('ionTabDidChange', { detail: { tab: e.detail.tab } }));
|
||||
}
|
||||
this.setActiveTabOnContext(e.detail.tab);
|
||||
this.context.changeTab(e.detail.tab, currentHref, e.detail.routeOptions);
|
||||
if (this.props.routerOutletRef?.current) {
|
||||
this.setActiveTabOnContext(e.detail.tab);
|
||||
this.context.changeTab(e.detail.tab, currentHref, e.detail.routeOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ export const IonTabBar = defineComponent({
|
||||
};
|
||||
},
|
||||
updated() {
|
||||
this.setupTabState(inject("navManager"));
|
||||
this.setupTabState(inject("navManager", null));
|
||||
},
|
||||
methods: {
|
||||
setupTabState(ionRouter: any) {
|
||||
@ -127,13 +127,13 @@ export const IonTabBar = defineComponent({
|
||||
*/
|
||||
checkActiveTab(ionRouter: any) {
|
||||
const hasRouterOutlet = this.$props._hasRouterOutlet;
|
||||
const currentRoute = ionRouter.getCurrentRouteInfo();
|
||||
const currentRoute = ionRouter?.getCurrentRouteInfo();
|
||||
const childNodes = this.$data.tabVnodes;
|
||||
const { tabs, activeTab: prevActiveTab } = this.$data.tabState;
|
||||
const tabKeys = Object.keys(tabs);
|
||||
let activeTab = tabKeys.find((key) => {
|
||||
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)
|
||||
);
|
||||
},
|
||||
|
@ -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 () => {
|
||||
|
Reference in New Issue
Block a user