Ionic Page Caching: Where to Refresh Data When Back Navigation Skips ngOnInit
Ionic's ion-router-outlet keeps visited pages mounted, so ngOnInit does not re-run on back navigation. Here is where to refresh data and clean up.
20 Jan 2026, 15:17 UTC

The stale list after a back navigation
You have a list page that navigates to a detail page. On the detail page you edit an item, tap back, and the list still shows the old value. The component's initialization hook — Angular's ngOnInit, a React effect with an empty dependency array, or Vue's mounted — did not run again. That is not a bug in your data layer. It is Ionic's router outlet doing what it was designed to do.
Ionic's ion-router-outlet keeps previously visited route components mounted in the DOM instead of destroying them. Back navigation reuses the existing component instance, which is why the transition feels instant and scroll position is preserved. The practical consequence: treat cached pages as long-lived components, not as components that are created fresh on every visit.
Ionic lifecycle events vs framework hooks
Ionic exposes its own lifecycle events that fire around navigation transitions. They are the supported place to refresh volatile data or reset transient UI state. The exact registration style differs by framework integration and Ionic major version, so confirm names and signatures against the documentation for the version you ship.
| Event | When it fires | Typical use |
|---|---|---|
ionViewWillEnter | Before the page is about to enter and become active | Refetch volatile data; runs on first load and on return |
ionViewDidEnter | After the page has fully entered and is active | Start animations or work that needs the page visible |
ionViewWillLeave | Before the page is about to leave and stop being active | Pause timers or stop work that should not run in background |
ionViewDidLeave | After the page has finished leaving | Cleanup that should happen after the transition |
ionViewWillUnmount | Before the page is destroyed and removed from the cache | Unsubscribe, clear intervals, remove listeners |
Framework hooks still matter. Keep expensive one-time setup in framework initialization, refetch volatile data on enter, and release subscriptions, timers, and listeners on leave or unmount. Do not assume ionViewWillLeave covers app backgrounding, tab switches, or browser tab changes — those are separate concerns.
A worked example: refresh on enter, subscribe once, clean up on unmount
The example below is an Angular page component. In React, the same events are exposed as hooks such as useIonViewWillEnter; in Vue, as composition functions such as onIonViewWillEnter. Check your integration's docs for exact names.
// src/app/pages/list/list.page.ts
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { DataService } from '../../services/data.service';
@Component({ selector: 'app-list', templateUrl: './list.page.html' })
export class ListPage implements OnInit, OnDestroy {
items: Item[] = [];
private sub?: Subscription;
constructor(private data: DataService) {}
ngOnInit() {
// One-time setup only. Does not re-run on back navigation.
this.sub = this.data.changes$.subscribe(() => {
this.items = this.data.snapshot();
});
}
ionViewWillEnter() {
// Runs on first load AND on back navigation.
// Guard against duplicate fetches if refresh also emits changes$.
this.data.refresh();
}
ionViewWillUnmount() {
this.sub?.unsubscribe();
}
ngOnDestroy() {
// Framework destroy may not run for cached pages.
// Keep this for safety, but do not rely on it for cache cleanup.
this.sub?.unsubscribe();
}
}
Where to run it: edit the page component file in your Ionic project, then rebuild or reload the dev server. No special permissions are required. Placeholders: DataService, changes$, refresh(), and Item are your own service, observable, method, and model names.
Expected check: open the list, navigate to detail, edit an item, and navigate back. The refetch call in ionViewWillEnter should run on the return trip, so the list reflects the edit. If your refresh() also pushes into changes$, you may see a duplicate fetch or double subscription; add a guard flag or make the subscription idempotent.
The trade-off: instant back button vs predictable state
Caching makes back navigation feel instant and preserves scroll position, but it also keeps memory and stale state alive. Cached pages retain DOM nodes and JavaScript state. Long sessions with many visited routes can grow memory, so test on low-end devices rather than assuming desktop performance is representative.
Forcing page recreation trades that performance for more predictable state at the cost of extra work on every visit. The mechanism for doing so is framework- and version-specific — for example, route reuse strategy in Angular — so check the docs before changing it. For most data-refresh problems, moving the refetch to ionViewWillEnter is the smaller, more supported change.
How to verify the behavior in your app
- Build a two-page flow. Add logging to every Ionic lifecycle event and every framework hook you care about. Navigate forward, back, and via a tab switch, and record which events fire and in what order.
- Edit data on the detail page, navigate back, and confirm the list reflects the change only when the refetch is placed in
ionViewWillEnter. If it also updates with the refetch removed, something else is refreshing the list. - Inspect the DOM in devtools after several navigations. Earlier page elements should remain attached under
ion-router-outlet. Then watch memory across repeated cycles to see whether cached pages accumulate. - Check the Ionic documentation for your major version and framework integration to confirm event names, signatures, and any deprecations. Lifecycle event names and availability differ across Ionic major versions.
Actionable takeaway: put volatile refetches in ionViewWillEnter, keep one-time setup in framework initialization, and release subscriptions, timers, and listeners in ionViewWillUnmount. Log the events once in your own app before trusting any pattern, because the exact order and availability depend on your Ionic version and framework.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.