I have react-router set up and a Switch component that renders some Page components. All my components render the same layout (for now. Later it will be parametric). My page components "inject" content to the layout so I can't have the layout component wrap my outer switch component. It has to be used as a child from within the page components.
// Sample code:
// app.js
const App = () => (
<LanguageProvider defaultLanguage="el" languages={languages}>
<PathProvider>
<MenuProvider menu={appMenu}>
<TemplateProvider injectedComponents={uiComponentOverrides} toolBar={toolBar}>
<Switch>
<Redirect exact from="/" to="dashboard" />
<Route exact path="/dashboard" component={DashboardIndex} />
<Route exact path="/overview" component={OverviewIndex} />
<Route exact path="/federation" component={FederationIndex} />
<Route exact path="/clubs" component={ClubsIndex} />
<Route exact path="/athletes" component={AthletesIndex} />
<Route exact path="/athletes/:id" component={AthleteDetails} />
<Route exact path="/officials" component={OfficialsIndex} />
<Route component={EmptyPage} />
</Switch>
</TemplateProvider>
</MenuProvider>
</PathProvider>
</LanguageProvider>
);
// Sample of a page component
// dashboard-page.js
export const DashboardIndex = () => {
const { t } = useTranslation();
return (
<AppFullPage key="page-component" title={t('Home.Index.WelcomeTitle')}>
<p>Dashboard content</p>
</AppFullPage>
);
};
// The AppFullPage component is the layout component. Content is injected to it through the title, subtitle, toolbar, menu and children props.
Even though the final html render is the same from the layout skeleton (it only differs inside the slot parts of the layout), react unmounts and remounts the whole layout tree.
I can understand react re-rendering the whole tree. React sees a different top component (the page component is different for every location). So react renders the new component and creates a new virtual dom.
What I can't understand is unmounting and remounting of the top html elements since they didn't change. The top div didn't change. The language picker dropdown in my header menu didn't change. The application menu in the left didn't change. Yes, they where rendered from different components but they are the same output.
If react compares the outputs of successive renders and only changes what is needed, then why the components are unmounted and remounted?
This behavior breaks animations and other behavior of components (eg I would like a dropdown in the common layout space to remain open even after a page change, but since it is unmounted and remounted, it loses state).
How can I instruct react to not remount identical components?
Or
How can I achieve my goal of letting the page inject content in the layout?
Is using portals a candidate for a solution?