vaadin / framework

Vaadin 6, 7, 8 is a Java framework for modern Java web applications.
http://vaadin.com/
Other
1.78k stars 729 forks source link

Pressing F5 in browser on UI with PreserveOnRefresh will re-create the view #11614

Closed mvysny closed 5 years ago

mvysny commented 5 years ago

When F5 is pressed in a browser with Vaadin app having @PreserveOnRefresh on the UI, I expect that the UI including any of the child components will not be re-created on server-side. However, starting with Vaadin 8.7.0-8.8.2 as a result of https://github.com/vaadin/framework/issues/11416 the UI.doRefresh() calls navigator.navigateTo() to the current URL, which re-creates the view. The issue is demonstrated in the example app attached.

mvysny commented 5 years ago

vaadin8-app.zip

Run the app and press F5. The app shows the text This is instance no 1; view's constructor increases the integer. I expect that F5 would not re-create the view, and thus after F5 the text should still read This is instance no 1. However, currently the constructor is re-run and the text will read This is instance no 2.

mvysny commented 5 years ago

The issue is even worse if the view's attach listener shows a Window. Those windows then start to multiply as the user presses F5 (since the UI preserves the prior windows).

TatuLund commented 5 years ago

I tested this, and your finding is correct. This is clearly a regression from that fix.

mvysny commented 5 years ago

I believe that the patch will not work in all cases. Please consider the following scenario:

  1. The user opens the root view, oldNavigationState is null
  2. The user presses F5. oldNavigationState is set to current navigator state which is "". The navigation is not performed (this is proper behavior)
  3. The user clicks a button which uses Navigator to navigate to MyView. oldNavigationState is still "" since doRefresh() was not called.
  4. The user presses F5. oldNavigationState is "" but the current navigator state comes from browser's URL which is my-view, and alas the view is reinstantiated.

To fix this, we probably need to remember the oldNavigationState in the Navigator (it would be the currentNavigationState for which the View is instantiated). Then, we only navigate in doRefresh() if the current view's currentNavigationState is different than the browser's URL. The Navigator needs to keep track to currentNavigationState as it performs navigation and view instantiation.