Preserving the State on Refresh
When a URL is entered into a browser, Vaadin’s routing subsystem resolves it into a view component by inspecting @Route class annotations. By default, a new instance is created when a matching class is found. This also happens when the user refreshes the page in the same browser tab. However, in certain situations you may want to keep the state of the view when it’s refreshed.
One such situation might be if the view contains many data entry components, and the user is likely to refresh the page — intentionally or unintentionally — before the data is saved on the backend. By preserving the view, you ensure that the data entries aren’t lost and therefore provide a better user experience.
Another use case is supporting browser, tab-specific "sessions" as an alternative to the standard cookie-based session. The @PreserveOnRefresh
annotation instructs Vaadin to reuse the view component of a route whenever the route is reloaded in the same browser tab. The routed component instance is then the same server-side object that was created in the first request, with all its state preserved — such as member fields, subcomponent hierarchy, and so on.
Preserving the State of a Component
To cause a single-view component to preserve its content on refresh, add the @PreserveOnRefresh
annotation to the class.
Example: Adding the @PreserveOnRefresh
annotation to the PreservedView
class.
@Route("myview")
@PreserveOnRefresh
public class PreservedView extends VerticalLayout {
public PreservedView() {
add(new TextField("Content will be preserved"));
// ...
}
}
If the view component has a router layout via the layout
parameter of the @Route
annotation, the router layout is also preserved on refresh. As an alternative, you can add the @PreserveOnRefresh
annotation to a class that implements RouterLayout
.
Example: Adding the @PreserveOnRefresh
annotation to an implementation of RouterLayout
.
@PreserveOnRefresh
public class PreservedLayout extends FlexLayout
implements RouterLayout {
public PreservedLayout() {
// ...
}
}
-
The
PreservedLayout
instance itself, as well as any view laid out inside it, is preserved on refresh.
Any elements that aren’t direct children of the view component, such as notifications and dialogs, are also preserved. This means that if your @PreserveOnRefresh
annotated view class opens a dialog in which the user makes edits and then refreshes, the dialog remains visible in its edited state.
Preconditions and Limitations
Using the @PreserveOnRefresh
annotation has some conditions and limitations. They are as follows:
-
The annotation must be placed in a component class that’s a route target — typically annotated with
@Route
— or on a component that implementsRouterLayout
. -
The annotation doesn’t support partial preserving. You can’t preserve only some components on the route chain. If the annotation is present on any component in the chain, the entire chain is preserved.
-
The component is made to persist only when reloaded in the same browser tab — the
window.name
client-side property is used to identify the tab — and only if the URL stays the same. Visiting another route or changing a URL parameter discards the component state permanently. -
Vaadin 10 and later don’t preserve the
UI
instance between refreshes. The view is detached from its previousUI
and then attached to a freshedUI
instance on refresh. -
The
AttachEvent
andDetachEvent
events are also generated when a preserved component is moved to a newUI
. As a consequence, during the lifetime of a view component, it should expect multiple calls toonAttach()
and listeners registered throughaddAttachListener()
. -
Navigation lifecycle events
BeforeEnterEvent
andAfterNavigationEvent
are generated on refresh. The methodisRefreshEvent
can be used to distinguish a refresh of the view so that any data updates can be skipped.
DABDBD3E-00C4-475C-A425-50B1AC48283E