Reputation: 628
I have a situation where few routes consists of the same component and I want to preserve its state, but with this behavior it's fairly impossible.
Live example (look at seconds elapsed): https://csb-43lp1km647-nkiinaibit.now.sh
CodeSandbox: https://codesandbox.io/s/43lp1km647
Of course I could save and restore state of timer while changing routes, but my app has an infinite CSS transition as a background (not on every route).
I was trying adding keys, even portal, but it still remounts everything.
Is there any way to enforce typical React's reconciliation (remount only elements that have to be remounted)?
Update:
Just found out that <Switch />
will render everything until it finds element that matches, and that could be either a certain <Route />
or any element except it's inside <Fragment />
.
Code:
<Router history={history}>
<Switch>
<Route path="/third" component={RouteWithoutTimer} />
<React.Fragment>
<Timer />
<Route exact path="/" component={FirstRoute} />
<Route path="/second" component={SecondRoute} />
</React.Fragment>
</Switch>
</Router>
Or with wildcard route:
<Router history={history}>
<Switch>
<Route path="/third" component={RouteWithoutTimer} />
<React.Fragment>
<Timer />
<Switch>
<Route exact path="/" component={FirstRoute} />
<Route component={NotFoundRoute} />
</Switch>
</React.Fragment>
</Switch>
</Router>
It's not a solution I was looking for, but it works fine.
Upvotes: 10
Views: 676
Reputation: 3766
This is where the state management libraries come to scene.
In React, states are per component and has lifecycle of it's owned component, so when router destructs/remounts the component, you lose all the data. I advice you to migrate your state to a state management library like redux
as soon as possible. Otherwise your code can be mess if this is a medium-sized application.
Upvotes: 2
Reputation: 11260
You are mounting a new instance of Timer
in each route.
If you want to share a component across routes, you should lift it to the parent component of the routes:
<React.Fragment>
<Timer />
<Switch>
<Route exact path="/" component={FirstRoute} />
<Route path="/second" component={SecondRoute} />
</Switch>
</React.Fragment>
Upvotes: 2