From 5a3b63bf7a040dd3fdae71628f162fffe59e5a20 Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Mon, 9 Oct 2023 17:37:33 -0400 Subject: [PATCH 1/3] fix(react): lifecycle events are removed on page unmount Co-authored-by: Maria Hutt --- .../react/src/routing/OutletPageManager.tsx | 27 +++++++++++++------ packages/react/src/routing/PageManager.tsx | 27 +++++++++++++------ 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/packages/react/src/routing/OutletPageManager.tsx b/packages/react/src/routing/OutletPageManager.tsx index ea77c0c625c..da35a220afb 100644 --- a/packages/react/src/routing/OutletPageManager.tsx +++ b/packages/react/src/routing/OutletPageManager.tsx @@ -24,6 +24,17 @@ export class OutletPageManager extends React.Component { super(props); this.outletIsReady = false; + + /** + * This binds the scope of the following methods to the class scope. + * The `.bind` method returns a new function, so we need to assign it + * in the constructor to avoid creating a new function when removing the + * event listeners. + */ + this.ionViewWillEnterHandler = this.ionViewWillEnterHandler.bind(this); + this.ionViewDidEnterHandler = this.ionViewDidEnterHandler.bind(this); + this.ionViewWillLeaveHandler = this.ionViewWillLeaveHandler.bind(this); + this.ionViewDidLeaveHandler = this.ionViewDidLeaveHandler.bind(this); } componentDidMount() { @@ -39,19 +50,19 @@ export class OutletPageManager extends React.Component { }); } - this.ionRouterOutlet.addEventListener('ionViewWillEnter', this.ionViewWillEnterHandler.bind(this)); - this.ionRouterOutlet.addEventListener('ionViewDidEnter', this.ionViewDidEnterHandler.bind(this)); - this.ionRouterOutlet.addEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler.bind(this)); - this.ionRouterOutlet.addEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler.bind(this)); + this.ionRouterOutlet.addEventListener('ionViewWillEnter', this.ionViewWillEnterHandler); + this.ionRouterOutlet.addEventListener('ionViewDidEnter', this.ionViewDidEnterHandler); + this.ionRouterOutlet.addEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler); + this.ionRouterOutlet.addEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler); } } componentWillUnmount() { if (this.ionRouterOutlet) { - this.ionRouterOutlet.removeEventListener('ionViewWillEnter', this.ionViewWillEnterHandler.bind(this)); - this.ionRouterOutlet.removeEventListener('ionViewDidEnter', this.ionViewDidEnterHandler.bind(this)); - this.ionRouterOutlet.removeEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler.bind(this)); - this.ionRouterOutlet.removeEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler.bind(this)); + this.ionRouterOutlet.removeEventListener('ionViewWillEnter', this.ionViewWillEnterHandler); + this.ionRouterOutlet.removeEventListener('ionViewDidEnter', this.ionViewDidEnterHandler); + this.ionRouterOutlet.removeEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler); + this.ionRouterOutlet.removeEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler); } } diff --git a/packages/react/src/routing/PageManager.tsx b/packages/react/src/routing/PageManager.tsx index 8c12b460ac4..090c717ae13 100644 --- a/packages/react/src/routing/PageManager.tsx +++ b/packages/react/src/routing/PageManager.tsx @@ -23,6 +23,17 @@ export class PageManager extends React.PureComponent { this.ionPageElementRef = React.createRef(); // React refs must be stable (not created inline). this.stableMergedRefs = mergeRefs(this.ionPageElementRef, this.props.forwardedRef); + + /** + * This binds the scope of the following methods to the class scope. + * The `.bind` method returns a new function, so we need to assign it + * in the constructor to avoid creating a new function when removing the + * event listeners. + */ + this.ionViewWillEnterHandler = this.ionViewWillEnterHandler.bind(this); + this.ionViewDidEnterHandler = this.ionViewDidEnterHandler.bind(this); + this.ionViewWillLeaveHandler = this.ionViewWillLeaveHandler.bind(this); + this.ionViewDidLeaveHandler = this.ionViewDidLeaveHandler.bind(this); } componentDidMount() { @@ -31,19 +42,19 @@ export class PageManager extends React.PureComponent { this.ionPageElementRef.current.classList.add('ion-page-invisible'); } this.context.registerIonPage(this.ionPageElementRef.current, this.props.routeInfo!); - this.ionPageElementRef.current.addEventListener('ionViewWillEnter', this.ionViewWillEnterHandler.bind(this)); - this.ionPageElementRef.current.addEventListener('ionViewDidEnter', this.ionViewDidEnterHandler.bind(this)); - this.ionPageElementRef.current.addEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler.bind(this)); - this.ionPageElementRef.current.addEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler.bind(this)); + this.ionPageElementRef.current.addEventListener('ionViewWillEnter', this.ionViewWillEnterHandler); + this.ionPageElementRef.current.addEventListener('ionViewDidEnter', this.ionViewDidEnterHandler); + this.ionPageElementRef.current.addEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler); + this.ionPageElementRef.current.addEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler); } } componentWillUnmount() { if (this.ionPageElementRef.current) { - this.ionPageElementRef.current.removeEventListener('ionViewWillEnter', this.ionViewWillEnterHandler.bind(this)); - this.ionPageElementRef.current.removeEventListener('ionViewDidEnter', this.ionViewDidEnterHandler.bind(this)); - this.ionPageElementRef.current.removeEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler.bind(this)); - this.ionPageElementRef.current.removeEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler.bind(this)); + this.ionPageElementRef.current.removeEventListener('ionViewWillEnter', this.ionViewWillEnterHandler); + this.ionPageElementRef.current.removeEventListener('ionViewDidEnter', this.ionViewDidEnterHandler); + this.ionPageElementRef.current.removeEventListener('ionViewWillLeave', this.ionViewWillLeaveHandler); + this.ionPageElementRef.current.removeEventListener('ionViewDidLeave', this.ionViewDidLeaveHandler); } } From 459b38cdb7df213545082381edd49e3f803a2f25 Mon Sep 17 00:00:00 2001 From: Sean Perkins <13732623+sean-perkins@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:09:21 -0400 Subject: [PATCH 2/3] Update packages/react/src/routing/OutletPageManager.tsx Co-authored-by: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com> --- packages/react/src/routing/OutletPageManager.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react/src/routing/OutletPageManager.tsx b/packages/react/src/routing/OutletPageManager.tsx index da35a220afb..0e0d1f9ea08 100644 --- a/packages/react/src/routing/OutletPageManager.tsx +++ b/packages/react/src/routing/OutletPageManager.tsx @@ -28,8 +28,8 @@ export class OutletPageManager extends React.Component { /** * This binds the scope of the following methods to the class scope. * The `.bind` method returns a new function, so we need to assign it - * in the constructor to avoid creating a new function when removing the - * event listeners. + * in the constructor rather than when adding or removing the listeners + * to avoid creating a new function. */ this.ionViewWillEnterHandler = this.ionViewWillEnterHandler.bind(this); this.ionViewDidEnterHandler = this.ionViewDidEnterHandler.bind(this); From d5782c828ef24db1401687199871e7af42a19f8e Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Wed, 11 Oct 2023 16:10:13 -0400 Subject: [PATCH 3/3] chore: apply same comment to pagemanager --- packages/react/src/routing/PageManager.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react/src/routing/PageManager.tsx b/packages/react/src/routing/PageManager.tsx index 090c717ae13..1ba3f94b98f 100644 --- a/packages/react/src/routing/PageManager.tsx +++ b/packages/react/src/routing/PageManager.tsx @@ -27,8 +27,8 @@ export class PageManager extends React.PureComponent { /** * This binds the scope of the following methods to the class scope. * The `.bind` method returns a new function, so we need to assign it - * in the constructor to avoid creating a new function when removing the - * event listeners. + * in the constructor rather than when adding or removing the listeners + * to avoid creating a new function. */ this.ionViewWillEnterHandler = this.ionViewWillEnterHandler.bind(this); this.ionViewDidEnterHandler = this.ionViewDidEnterHandler.bind(this);