diff --git a/packages/react/src/components/navigation/IonNav.tsx b/packages/react/src/components/navigation/IonNav.tsx index 1c5955fc57..8d2ca03e3a 100644 --- a/packages/react/src/components/navigation/IonNav.tsx +++ b/packages/react/src/components/navigation/IonNav.tsx @@ -1,6 +1,6 @@ import type { FrameworkDelegate, JSX } from '@ionic/core/components'; import { defineCustomElement } from '@ionic/core/components/ion-nav.js'; -import React, { useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { ReactDelegate } from '../../framework-delegate'; import { createReactComponent } from '../react-component-lib'; @@ -25,10 +25,10 @@ const IonNavInternal: React.FC = ({ children, forwardedRef, ...rest * Allows us to create React components that are rendered within * the context of the IonNav component. */ - const addView = (view: React.ReactElement) => setViews([...views, view]); - const removeView = (view: React.ReactElement) => setViews(views.filter((v) => v !== view)); + const addView = (view: React.ReactElement) => setViews((existingViews) => [...existingViews, view]); + const removeView = (view: React.ReactElement) => setViews((existingViews) => existingViews.filter((v) => v !== view)); - const delegate = ReactDelegate(addView, removeView); + const delegate = useMemo(() => ReactDelegate(addView, removeView), []); return ( diff --git a/packages/react/src/framework-delegate.tsx b/packages/react/src/framework-delegate.tsx index b26cc6d18e..dcb4823ef0 100644 --- a/packages/react/src/framework-delegate.tsx +++ b/packages/react/src/framework-delegate.tsx @@ -9,7 +9,7 @@ export const ReactDelegate = ( addView: (view: React.ReactElement) => void, removeView: (view: React.ReactElement) => void ): FrameworkDelegate => { - const refMap = new WeakMap(); + const refMap = new WeakMap(); const attachViewToDom = async ( parentElement: HTMLElement, @@ -24,17 +24,19 @@ export const ReactDelegate = ( const componentWithProps = component(propsOrDataObj); const hostComponent = createPortal(componentWithProps, div); - refMap.set(component, hostComponent); + refMap.set(div, hostComponent); addView(hostComponent); return Promise.resolve(div); }; - const removeViewFromDom = (_container: any, component: ReactComponent): Promise => { + const removeViewFromDom = (_container: any, component: HTMLElement): Promise => { const hostComponent = refMap.get(component); hostComponent && removeView(hostComponent); + component.remove(); + return Promise.resolve(); }; diff --git a/packages/react/test/base/tests/e2e/specs/navigation/IonNav.cy.ts b/packages/react/test/base/tests/e2e/specs/navigation/IonNav.cy.ts index 2df509984f..e0940bd3b9 100644 --- a/packages/react/test/base/tests/e2e/specs/navigation/IonNav.cy.ts +++ b/packages/react/test/base/tests/e2e/specs/navigation/IonNav.cy.ts @@ -15,6 +15,8 @@ describe('IonNav', () => { cy.get('ion-button').contains('Go to Page Two').click(); cy.get('#pageTwoContent').should('be.visible'); cy.get('ion-nav').contains('Page two content'); + + cy.get('ion-nav .ion-page').should('have.length', 2); }); it('should pop a page', () => { @@ -23,10 +25,14 @@ describe('IonNav', () => { cy.get('#pageTwoContent').should('be.visible'); cy.get('ion-nav').contains('Page two content'); + cy.get('ion-nav .ion-page').should('have.length', 2); + cy.get('.ion-page.can-go-back ion-back-button').click(); cy.get('#pageOneContent').should('be.visible'); cy.get('ion-nav').contains('Page one content'); + + cy.get('ion-nav .ion-page').should('have.length', 1); }); it('should pass params to the page', () => {