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. --> While debugging #28186, Maria and I identified that Ionic's lifecycle event listeners (`ionViewWillEnter`, etc.) were being registered multiple times on the same `.ion-page` element. This resulted in problematic behavior, where a user's implementation of our lifecycle hooks, would execute their callback multiple times. ```ts useIonViewWillEnter(() => { // This is called 2x for every time the `ionViewWillEnter` event is emitted (in React 18, dev mode) console.log('hello world'); }); ``` When the Ionic lifecycle event listeners are registered in React, we bind the scope of the class to the callback function. When removing the event listener we additional use the `.bind` syntax. ```tsx componentDidMount() { element.addEventListener('ionViewWillEnter', this.ionViewWillEnter.bind(this)); } componentWillUnmount() { // This creates a new instance of the function to remove! It doesn't remove the original event listener. element.removeEventListener('ionViewWillEnter', this.ionViewWillEnter.bind(this)); } ``` The `.bind` method returns a new instance of the function. This means in the implementation we are creating a new instance of the function when both adding and removing the event listener - resulting in the `removeEventListener` to never remove the original event listener. This behavior only occurred in React 18 in dev mode, as a result of the mount/unmount behavior running 2x for `useEffect` hooks. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - Ionic lifecycle event listeners are removed from element references when they are unmounted. - User's lifecycle callback methods are only invoked once per event emission. |Before|After| |----|----| |<img alt="CleanShot 2023-10-09 at 18 32 08@2x" src="https://github.com/ionic-team/ionic-framework/assets/13732623/53f2ef5d-5900-4a84-b427-fa6c9d35d081">|<img alt="CleanShot 2023-10-09 at 18 29 37@2x" src="https://github.com/ionic-team/ionic-framework/assets/13732623/c8a9a657-a0bf-4d6d-9f21-a41a686de490">| ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> --------- Co-authored-by: Maria Hutt <maria@ionic.io> Co-authored-by: Amanda Johnston <90629384+amandaejohnston@users.noreply.github.com>
@ionic/react
These are React specific building blocks on top of @ionic/core components/services.
To get started, install the Ionic CLI by running npm i -g @ionic/cli. Then, start a new Ionic React Project by running ionic start myapp --type=react.
Publishing a Native Application
You can now make use of all of the ionic components in your React application. If you want to publish your app to the App Store or Google Play you will need to use the ionic cli to execute Capacitor commands to do so.
More information on this can be found here. https://ionicframework.com/docs/cli If you want to learn more about Capacitor our dedicated site can be found here. https://capacitor.ionicframework.com/
The commands that you will need to execute are below in your project's root.
ionic init "My React App" --type=react
ionic integrations enable capacitor
Then run the following command to get started with either ios or android platforms.
ionic capacitor add <android|ios>
After build you build your app you will need to copy your capacitor resources into the build dir so execute the following command.
ionic capacitor copy
To open your application to build/emulate in Android Studio or Xcode run the open command.
ionic capacitor open <android|ios>