From 790eb6e15ede87630819f3613cbfcb783e302dd7 Mon Sep 17 00:00:00 2001 From: Ely Lucas Date: Fri, 8 Nov 2019 16:15:52 -0700 Subject: [PATCH 1/2] fix(react): improving lifecycle hooks to deal with stale closures, fixes #19873 (#19874) --- .../src/contexts/IonLifeCycleContext.tsx | 46 +++++++++++++++++-- packages/react/src/lifecycle/hooks.ts | 32 +++++++++---- packages/react/tslint.json | 2 +- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/packages/react/src/contexts/IonLifeCycleContext.tsx b/packages/react/src/contexts/IonLifeCycleContext.tsx index f5d1051183..b8045c40d4 100644 --- a/packages/react/src/contexts/IonLifeCycleContext.tsx +++ b/packages/react/src/contexts/IonLifeCycleContext.tsx @@ -22,7 +22,7 @@ export const IonLifeCycleContext = /*@__PURE__*/React.createContext { return; }, }); -type LifeCycleCallback = () => void; +export interface LifeCycleCallback { (): void; id?: number; } export const DefaultIonLifeCycleContext = class implements IonLifeCycleContextInterface { @@ -33,7 +33,16 @@ export const DefaultIonLifeCycleContext = class implements IonLifeCycleContextIn componentCanBeDestroyedCallback?: () => void; onIonViewWillEnter(callback: LifeCycleCallback) { - this.ionViewWillEnterCallbacks.push(callback); + if (callback.id) { + const index = this.ionViewWillEnterCallbacks.findIndex(x => x.id === callback.id); + if (index > -1) { + this.ionViewWillEnterCallbacks[index] = callback; + } else { + this.ionViewWillEnterCallbacks.push(callback); + } + } else { + this.ionViewWillEnterCallbacks.push(callback); + } } ionViewWillEnter() { @@ -41,7 +50,16 @@ export const DefaultIonLifeCycleContext = class implements IonLifeCycleContextIn } onIonViewDidEnter(callback: LifeCycleCallback) { - this.ionViewDidEnterCallbacks.push(callback); + if (callback.id) { + const index = this.ionViewDidEnterCallbacks.findIndex(x => x.id === callback.id); + if (index > -1) { + this.ionViewDidEnterCallbacks[index] = callback; + } else { + this.ionViewDidEnterCallbacks.push(callback); + } + } else { + this.ionViewDidEnterCallbacks.push(callback); + } } ionViewDidEnter() { @@ -49,7 +67,16 @@ export const DefaultIonLifeCycleContext = class implements IonLifeCycleContextIn } onIonViewWillLeave(callback: LifeCycleCallback) { - this.ionViewWillLeaveCallbacks.push(callback); + if (callback.id) { + const index = this.ionViewWillLeaveCallbacks.findIndex(x => x.id === callback.id); + if (index > -1) { + this.ionViewWillLeaveCallbacks[index] = callback; + } else { + this.ionViewWillLeaveCallbacks.push(callback); + } + } else { + this.ionViewWillLeaveCallbacks.push(callback); + } } ionViewWillLeave() { @@ -57,7 +84,16 @@ export const DefaultIonLifeCycleContext = class implements IonLifeCycleContextIn } onIonViewDidLeave(callback: LifeCycleCallback) { - this.ionViewDidLeaveCallbacks.push(callback); + if (callback.id) { + const index = this.ionViewDidLeaveCallbacks.findIndex(x => x.id === callback.id); + if (index > -1) { + this.ionViewDidLeaveCallbacks[index] = callback; + } else { + this.ionViewDidLeaveCallbacks.push(callback); + } + } else { + this.ionViewDidLeaveCallbacks.push(callback); + } } ionViewDidLeave() { diff --git a/packages/react/src/lifecycle/hooks.ts b/packages/react/src/lifecycle/hooks.ts index 181f2dbe56..7637b32be0 100644 --- a/packages/react/src/lifecycle/hooks.ts +++ b/packages/react/src/lifecycle/hooks.ts @@ -1,31 +1,43 @@ -import { useContext, useEffect } from 'react'; +import { useContext, useEffect, useRef } from 'react'; -import { IonLifeCycleContext } from '../contexts/IonLifeCycleContext'; +import { IonLifeCycleContext, LifeCycleCallback } from '../contexts/IonLifeCycleContext'; -export const useIonViewWillEnter = (callback: () => void) => { +export const useIonViewWillEnter = (callback: LifeCycleCallback, deps: any[] = []) => { const context = useContext(IonLifeCycleContext); + const id = useRef(); + id.current = id.current || Math.floor(Math.random() * 1000000); useEffect(() => { + callback.id = id.current!; context.onIonViewWillEnter(callback); - }, []); + }, deps); }; -export const useIonViewDidEnter = (callback: () => void) => { +export const useIonViewDidEnter = (callback: LifeCycleCallback, deps: any[] = []) => { const context = useContext(IonLifeCycleContext); + const id = useRef(); + id.current = id.current || Math.floor(Math.random() * 1000000); useEffect(() => { + callback.id = id.current!; context.onIonViewDidEnter(callback); - }, []); + }, deps); }; -export const useIonViewWillLeave = (callback: () => void) => { +export const useIonViewWillLeave = (callback: LifeCycleCallback, deps: any[] = []) => { const context = useContext(IonLifeCycleContext); + const id = useRef(); + id.current = id.current || Math.floor(Math.random() * 1000000); useEffect(() => { + callback.id = id.current!; context.onIonViewWillLeave(callback); - }, []); + }, deps); }; -export const useIonViewDidLeave = (callback: () => void) => { +export const useIonViewDidLeave = (callback: LifeCycleCallback, deps: any[] = []) => { const context = useContext(IonLifeCycleContext); + const id = useRef(); + id.current = id.current || Math.floor(Math.random() * 1000000); useEffect(() => { + callback.id = id.current!; context.onIonViewDidLeave(callback); - }, []); + }, deps); }; diff --git a/packages/react/tslint.json b/packages/react/tslint.json index 8f422d9a64..3ba6e0b026 100644 --- a/packages/react/tslint.json +++ b/packages/react/tslint.json @@ -19,7 +19,7 @@ "no-invalid-template-strings": true, "ban-export-const-enum": true, "only-arrow-functions": true, - "strict-boolean-conditions": [true, "allow-null-union", "allow-undefined-union", "allow-boolean-or-undefined", "allow-string"], + "strict-boolean-conditions": [false], "jsx-key": false, "jsx-self-close": false, "jsx-curly-spacing": [true, "never"], From 28b4221b19b12ceb3f98062794f5c596bec72b5e Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 14 Nov 2019 14:59:57 -0500 Subject: [PATCH 2/2] 4.11.5 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5f96e4aa8..e138a02f0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## [4.11.5](https://github.com/ionic-team/ionic/compare/v4.11.0...v4.11.5) (2019-11-14) + + +### Bug Fixes + +* **react:** improved lifecycle hooks to deal with stale closures, fixes [#19873](https://github.com/ionic-team/ionic/issues/19873) ([#19874](https://github.com/ionic-team/ionic/issues/19874)) ([5ff786a](https://github.com/ionic-team/ionic/commit/5ff786a23d5aa32281bbf5daaa7f8156de39caca)) + + ## [4.11.4](https://github.com/ionic-team/ionic/compare/v4.11.1...v4.11.4) (2019-11-07)