Ionic-framework: Loaded pages not cached? ionViewDidLoad called multiple times

Created on 20 Jun 2017  路  14Comments  路  Source: ionic-team/ionic-framework

Ionic version: (check one with "x")
[ ] 1.x (For Ionic 1.x issues, please use https://github.com/ionic-team/ionic-v1)
[ ] 2.x
[ x] 3.x

I'm submitting a ... (check one with "x")
[ x] bug report
[ ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or http://ionicworldwide.herokuapp.com/

Current behavior:
ionViewDidLoad is called every time a page is navigated to, it doesn't look like the page is cached. This is the case when setRoot or push are used. In other testing I've only seen pages cached when changing between tabs.

Expected behavior:
Once a page is "loaded" it should be cached and not recreated.

Steps to reproduce:
Run the plunkr, open the dev console, and click between the two menu items. You'll notice the ionViewDidLoad is called every time a page is clicked.

Related code:
http://plnkr.co/lIdPVA

Other information:
https://forum.ionicframework.com/t/entered-pages-not-cached-ionviewdidenter-called-multiple-times/95000

Ionic info: (run ionic info from a terminal/cmd prompt and paste output below):

global packages:

    @ionic/cli-plugin-proxy : 1.3.1
    @ionic/cli-utils        : 1.4.0
    Cordova CLI             : 7.0.1 
    Ionic CLI               : 3.4.0

local packages:

    @ionic/app-scripts              : 1.3.7
    @ionic/cli-plugin-cordova       : 1.4.0
    @ionic/cli-plugin-ionic-angular : 1.3.1
    Cordova Platforms               : android 6.2.3 ios 4.4.0
    Ionic Framework                 : ionic-angular 3.4.0

System:

    Node       : v7.4.0
    OS         : macOS Sierra
    Xcode      : Xcode 8.3.3 Build version 8E3004b 
    ios-deploy : 1.9.1 
    ios-sim    : 5.0.4 
    npm        : 4.0.5 

Most helpful comment

Sorry for responding to a CLOSED issues.

+1 for @saschwarz comments.

For me, I think it's more of an issue of what an end-user expects. If a page is loaded once, and the user navigates away, and later comes back to that page using the side menu, they would expect the view of that page to remain unchanged (aka not reloaded). As a dev, I don't mind the stack resetting, but I would highly appreciate optionally caching that view.

Also, keep in mind, PUSHing a new page on the stack leads to that target page having a left arrow (back arrow) in the header. Meaning, replacing .setRoot() calls with .push() leads to other complications.

All 14 comments

ionViewDidEnter() fires when you enter a page (even a cached one). ionViewDidLoad only fires when the page loaded, which is what you want to achieve. Also documented here: https://ionicframework.com/docs/api/navigation/NavController/

ionViewDidLoad: Runs when the page has loaded. This event only happens once per page being created. 
If a page leaves but is cached, then this event will not fire again on a subsequent viewing. 
The ionViewDidLoad event is good place to put your setup code for the page.

ionViewDidEnter: Runs when the page has fully entered and is now the active page. 
This event will fire, whether it was the first load or a cached page.

Sorry - yes. ionViewDidLoad fires every time. I'll update the title and description

I guess it depends on the use. If you are clicking items from a side menu, you may want the page to fully reload the data each time, but subsequent pushes/pops from that page shouldn't trigger reload of that page. Just like you want the previous pages to unload as you have now changed the context.

Clicking on the side menu is like a fresh request.

If you look at it from the context of an APP and not as a Website the functionality makes sense.

Like @davec21 mentioned, this is supposed to be this way.

Basicly you have an empty stack. Then you set the rootPage of that stack. Now there is one page on the stack. When you push another page onto it you will have two pages on the stack. Removing the pushed page will result in reusing the cached rootPage. Setting a new rootPage or pushing a page will always result in a freshly created page. This is how the lifecycle of an app is supposed to be.

Thank you both for your comments.

@davec21 IMO that's why ionViewWillEnter exists. I'd put any data refresh logic in that method. Then Angular data binding does its job and updates only the parts of the template that are affected. I figured having the separate methods would give me the choice as to when "expensive" operations occurred.

@digaus I guess I didn't expect the view caching to be coupled to the nav; though I can see how it would be convenient to implement that way. The view cache could live outside the nav stack and use an algorithm like LRU for evictions. It could help performance. I'm seeing complex pages take 100ms in the load, if they lived in a cache of (say) the latest half dozen pages it would help if they were revisited (at a cost of some additional memory - always a trade off...)

Problem is.. ionViewWillEnter gets called on pops. I wouldn't want my page to refresh on pop, but would want it to refresh on load. Yea, you could put some handlers in.. but it gets messy.

for example:

Product List Page -> Product Details -> Product List Page

I may want the product list page to load all products, clicking a product will push the details page, then if I just pop the details back to the list I don't need to reload all the data. However if I am in a different section of the app (Say Sports list) and come back to the Product list via side menu, I may want a refresh.

Clearly, my interpretation of when/how long a page could be cached is different than both of yours. Yours is the correct one (which my testing confirms) so maybe this needs to be converted to a documentation issue?

If wording was added to http://ionicframework.com/docs/api/navigation/NavController/ describing when cached pages are evicted it would help others who think like I do :smile:

Hello, everyone! @saschwarz navigation in Ionic is a pretty expansive subject, but I will try to sum up things here as best as possible. First, in my opinion, it is very helpful to look at navigation in an Ionic app using our NavController as being more similar to how navigation works in a native iOS or Android app than with the "traditional" router setup of something like a vanilla Angular app. When you tap to navigate to a page in the sidemenu it is calling setRoot. setRoot will remove the current page you are on from memory and reset the nav stack. Therefore, since setRoot is completely removing the page you were on from memory, the next time you go to that page the ionViewDidLoad lifecycle event will be called since the page is actually being loaded back into memory. The reasoning behind this is twofold. First, setRoot is meant to completely reset the navStack, and therefore it should remove pages from memory. Second, if we always kept every page a user navigated to in memory, memory usage would quickly get extremely high, especially with big apps. It is important to note that using pop and push does keep pages in memory as those methods are not resetting the nav stack, but simply navigating up and down the stack. All of this easily allows complex navigation, such as having multiple tabs with individual pages that can be navigated to from each of those tabs, without complicated router setup or anything of that sort.

Now that the theory is out of the way, this does sound like to me that it may be a documentation issue and because of that, @saschwarz I would urge you to open an issue here so that the docs person can look into this. Thanks everyone for using Ionic!

Thanks @jgw96 for the details.

I've created this doc issues: https://github.com/ionic-team/ionic-site/issues/1165

A quick clarification. As I mentioned: "The view cache _could_ live outside the nav stack and use an algorithm like LRU for evictions. It could help performance. I'm seeing complex pages take 100ms in the load, if they lived in a cache of (say) the latest half dozen pages it would help if they were revisited (at a cost of some additional memory - always a trade off...)". So you don't have to keep all the pages cached.

Maybe an enhancement would be to have a decorator to indicate that a page should remain cached even when it would normally be removed from the cache.

Your explanation also points to the need for improved documentation wrt push and pop: the key thing for the docs is push and pop don't actually keep the page being pushed or popped in memory. In my testing they keep the parent page in memory. I'm on rootPage and push(page1) all the lifecycle events fire in page and rootPage stays in memory. But when I pop from page1 then page1 is removed from memory (unload fires and didload does not fire for root as it's still cached). If rootPage subsequently calls push(page1) the ionViewDidLoad will fire again for page1 since it was removed from the cache during the pop.

Some examples of setRoot and push/pop showing the lifecycle method called on the parent/child would be very helpful in the documentation.

Sorry for responding to a CLOSED issues.

+1 for @saschwarz comments.

For me, I think it's more of an issue of what an end-user expects. If a page is loaded once, and the user navigates away, and later comes back to that page using the side menu, they would expect the view of that page to remain unchanged (aka not reloaded). As a dev, I don't mind the stack resetting, but I would highly appreciate optionally caching that view.

Also, keep in mind, PUSHing a new page on the stack leads to that target page having a left arrow (back arrow) in the header. Meaning, replacing .setRoot() calls with .push() leads to other complications.

I have the same problem too, in ionic 1 users search for product, page display search results, then he navigate away from the search page, when he click in tool bar to come back search page, ionic 1 provide view-cache=true.
However, when we migrate to ionic 2, that is no longer working, everytime user click back to search results, the state disappears.
I have request a feature from the ionic team, does not seem to move anywhere. [https://github.com/ionic-team/ionic/issues/13838#issuecomment-358617087]
[https://forum.ionicframework.com/t/enable-view-cache-for-ionic/118235]
I don't know ionic team try to ignore this solid case, I'm thinking of moving to React Native when It is availabe in npm 5.

Any news regarding this feature?

I too am hoping this is something that can be done fairly soon. Users are complaining that when they navigate away using the sidemenu and navigate back, the view is refreshed instead of left in it's previous state.

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DanailMinchev picture DanailMinchev  路  78Comments

marcovtwout picture marcovtwout  路  76Comments

abennouna picture abennouna  路  129Comments

vonovak picture vonovak  路  66Comments

TheMohanraj picture TheMohanraj  路  159Comments