mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
fix(react): IonTabButton will call custom onClick handlers (#25313)
Resolves #22511
This commit is contained in:
@ -178,12 +178,22 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
|
||||
}
|
||||
|
||||
private onTabButtonClick(
|
||||
e: CustomEvent<{ href: string; selected: boolean; tab: string; routeOptions: unknown }>
|
||||
e: CustomEvent<{ href: string; selected: boolean; tab: string; routeOptions: unknown }>,
|
||||
onClickFn?: (e: any) => void
|
||||
) {
|
||||
const tappedTab = this.state.tabs[e.detail.tab];
|
||||
const originalHref = tappedTab.originalHref;
|
||||
const currentHref = e.detail.href;
|
||||
const { activeTab: prevActiveTab } = this.state;
|
||||
|
||||
if (onClickFn) {
|
||||
/**
|
||||
* If the user provides an onClick function, we call it
|
||||
* with the original event.
|
||||
*/
|
||||
onClickFn(e);
|
||||
}
|
||||
|
||||
// this.props.onSetCurrentTab(e.detail.tab, this.props.routeInfo);
|
||||
// Clicking the current tab will bring you back to the original href
|
||||
if (prevActiveTab === e.detail.tab) {
|
||||
@ -232,7 +242,7 @@ class IonTabBarUnwrapped extends React.PureComponent<InternalProps, IonTabBarSta
|
||||
return React.cloneElement(child, {
|
||||
href,
|
||||
routeOptions,
|
||||
onClick: this.onTabButtonClick,
|
||||
onClick: (ev: CustomEvent) => this.onTabButtonClick(ev, child.props.onClick),
|
||||
});
|
||||
}
|
||||
return null;
|
||||
|
@ -34,6 +34,11 @@ export const IonTabButton = /*@__PURE__*/ (() =>
|
||||
}
|
||||
|
||||
render() {
|
||||
/**
|
||||
* onClick is excluded from the props, since it has a custom
|
||||
* implementation within IonTabBar.tsx. Calling onClick within this
|
||||
* component would result in duplicate handler calls.
|
||||
*/
|
||||
const { onClick, ...rest } = this.props;
|
||||
return (
|
||||
<IonTabButtonInner
|
||||
|
@ -0,0 +1,15 @@
|
||||
describe('IonTabs', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/tabs/tab1');
|
||||
});
|
||||
|
||||
it('should handle onClick handlers on IonTabButton', () => {
|
||||
const stub = cy.stub();
|
||||
|
||||
cy.on('window:alert', stub);
|
||||
cy.get('ion-tab-button[tab="tab1"]').click().then(() => {
|
||||
expect(stub.getCall(0)).to.be.calledWith('Tab was clicked')
|
||||
});
|
||||
|
||||
});
|
||||
});
|
@ -23,6 +23,7 @@
|
||||
"eject": "react-scripts eject",
|
||||
"sync": "sh ./scripts/sync.sh",
|
||||
"cypress": "cypress run --headless --browser chrome",
|
||||
"cypress.open": "cypress open",
|
||||
"e2e": "concurrently \"serve -s build -l 3000\" \"wait-on http-get://localhost:3000 && npm run cypress\" --kill-others --success first"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
@ -24,6 +24,7 @@ import './theme/variables.css';
|
||||
import Main from './pages/Main';
|
||||
import OverlayHooks from './pages/overlay-hooks/OverlayHooks';
|
||||
import OverlayComponents from './pages/overlay-components/OverlayComponents';
|
||||
import Tabs from './pages/Tabs';
|
||||
|
||||
setupIonicReact();
|
||||
|
||||
@ -34,6 +35,7 @@ const App: React.FC = () => (
|
||||
<Route path="/" component={Main} />
|
||||
<Route path="/overlay-hooks" component={OverlayHooks} />
|
||||
<Route path="/overlay-components" component={OverlayComponents} />
|
||||
<Route path="/tabs" component={Tabs} />
|
||||
</IonRouterOutlet>
|
||||
</IonReactRouter>
|
||||
</IonApp>
|
||||
|
@ -4,11 +4,10 @@ import {
|
||||
IonHeader,
|
||||
IonLabel,
|
||||
IonPage,
|
||||
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
IonItem,
|
||||
IonList
|
||||
IonList,
|
||||
} from '@ionic/react';
|
||||
|
||||
interface MainProps {}
|
||||
@ -32,6 +31,11 @@ const Main: React.FC<MainProps> = () => {
|
||||
<IonLabel>Overlay Components</IonLabel>
|
||||
</IonItem>
|
||||
</IonList>
|
||||
<IonList>
|
||||
<IonItem routerLink="/tabs">
|
||||
<IonLabel>Tabs</IonLabel>
|
||||
</IonItem>
|
||||
</IonList>
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
|
23
packages/react/test-app/src/pages/Tabs.tsx
Normal file
23
packages/react/test-app/src/pages/Tabs.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import { IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from '@ionic/react';
|
||||
import { Route, Redirect } from 'react-router';
|
||||
|
||||
interface TabsProps {}
|
||||
|
||||
const Tabs: React.FC<TabsProps> = () => {
|
||||
return (
|
||||
<IonTabs>
|
||||
<IonRouterOutlet>
|
||||
<Redirect from="/tabs" to="/tabs/tab1" exact />
|
||||
<Route path="/tabs/tab1" render={() => <IonLabel>Tab 1</IonLabel>} />
|
||||
</IonRouterOutlet>
|
||||
<IonTabBar slot="bottom">
|
||||
<IonTabButton tab="tab1" onClick={() => window.alert('Tab was clicked')}>
|
||||
<IonLabel>Click Handler</IonLabel>
|
||||
</IonTabButton>
|
||||
</IonTabBar>
|
||||
</IonTabs>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tabs;
|
Reference in New Issue
Block a user