RFC: preserve shared layout instances across withLayout route transitions
- Dominant language
- TypeScript
- Stars
- 8
- Forks
- 2
- Avg merge
- 13h 44m
- Merged PRs (30d)
- 1
Description
## Problem
`withLayout(Layout, views)` creates a separate wrapper view for every route view. When `createRoutesView` switches between two views from the same `withLayout` group, the previous wrapper is unmounted and the next wrapper is mounted.
As a result, the shared layout is not actually persistent:
- layout-local state is reset;
- effects and subscriptions are torn down and recreated;
- providers, navigation, sidebars, and other expensive shared UI remount;
- transitions between pages with the same visual shell can flicker.
The current React documentation explicitly notes that `withLayout` applies the same markup but does not guarantee that the layout remains mounted. A parent route with `Outlet` is a workaround, but it requires changing the route tree and does not naturally cover arbitrary route groups or exclusions.
Related documentation task: #29.
## Reproduction
```tsx
const RoutesView = createRoutesView({
routes: [
...withLayout(DashboardLayout, [
createRouteView({ route: routes.dashboard, view: DashboardPage }),
createRouteView({ route: routes.settings, view: SettingsPage }),
]),
createRouteView({ route: routes.signIn, view: SignInPage }),
],
});
```
1. Track mount and cleanup in `DashboardLayout`.
2. Navigate from `dashboard` to `settings`.
3. Observe that `DashboardLayout` is unmounted and mounted again, even though both views belong to the same layout group.
## Decision to make
Define whether persistent layout identity is part of the public RouteView contract and where it belongs:
- change `withLayout` from a per-view wrapper transform into a grouped/persistent view primitive;
- represent the layout as a parent RouteView and switch its content through an outlet;
- introduce an explicit layout/group identity that `createRoutesView` can preserve;
- or keep `withLayout` as a markup-only helper and introduce a separate persistence API.
The decision should also define:
- entering and leaving a layout group;
- multiple groups using the same layout component;
- nested and lazy route views;
- routes that intentionally have no layout;
- whether behavior is shared across React, Solid, and Vue or binding-specific;
- preservation of RouteView metadata such as `children`.
## Expected result
- Navigating between views in the same layout group does not remount the layout.
- The page content changes normally.
- Navigating to a view outside the group unmounts the layout.
- Regression tests count layout mounts/unmounts and cover group entry, internal transition, and exit.
Contributor guide
Assessment
This issue has not been assessed yet.