-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Switch is re-mounting the same component on route change #4578
Comments
This might have to do with the usage of |
Sanity check: Is this actually a problem? Mounting : unmounting !:: construction : destruction. Switch's goal should be just to juggle which Route is mounted based on the current location. The component is actually instantiated into an element by the render function of the Switch's container. |
@timdorr it's a common pattern to fetch data in |
Sorry, still not getting it (I'm trying!). What's the problem with that? If I've got some user profile page up, navigate away, the user posts some new content, and navigate back to the profile page, I would want to see that new content. So a fresh fetch from the lifecycle method would be good, no? |
@timdorr in my use-case the component needs to be persistent across several routes.
So, when you navigate across this routes, Makes sense now? :) |
Sort of. Why are you using a Switch for that? Just have a non-exact Route for the list: <Route path="/users" component={UserIndex} />
<Route path="/users/create" component={UserCreate} /> That would do the same thing. |
@timdorr this will render I want to render |
As I mentioned above, Switch can be replaced with an array of paths, passed to Route, but currently it's not supported (but working). <Route exact path={['/users', '/users/create']} component={UsersIndex} /> |
@timdorr I consider this a bug. @vladshcherbin Please let's not talk about array paths in here, that's a totally different conversation :) |
Hmm, maybe we don't use |
cloneElement shouldn't cause a remount, I was just looking at the code and I'm a bit stumped |
It's React.Children.toArray that causes this by setting the keys of the
(docs) Not sure exactly why this was added. If it's needed for flattening or sth, overwriting the key in Anyway, I think there are valid arguments for both behaviors, both in terms of how you'd initially expect it to work and in terms of what you want to do with it. Though it seems that with the suggested behavior, one could force the remount by themselves, which is not possible the other way around, e.g.: <Switch>
<Route render={() => <Comp key="1" />} />
<Route render={() => <Comp key="2" />} />
</Switch> |
Thanks @taurose your example:
feels more intuitive to me |
Here's a test case:
But I must be doing something wrong, because it passes... |
@timdorr I guess it is: ReactDOM.render((
<Router history={history}>
<div>
<Switch>
<Route exact path="/" component={App} />
<Route exact path="/foo" component={App} />
</Switch>
<Route path="/foo" component={() => <div />}/>
</div>
</Router>
), node) |
Oh, I'm totally missing things. The App component should not be remounted at all when switching between two component'ed Routes. I thought it was remounting too much just in general (not when going between two unique Routes). My bad... Let me work that into the test... |
OK, here's a failing test: it('does not remount a route', () => {
const node = document.createElement('div')
const history = createMemoryHistory({ initialEntries: ['/foo'] })
let mountCount = 0
class App extends React.Component {
componentWillMount() { mountCount++ }
render() { return <div /> }
}
ReactDOM.render((
<Router history={history}>
<Switch>
<Route path="/foo" component={App}/>
<Route path="/bar" component={App}/>
</Switch>
</Router>
), node)
expect(mountCount).toBe(1)
history.push('/bar')
expect(mountCount).toBe(1)
history.push('/foo')
expect(mountCount).toBe(1)
}) And changing the top of Switch's const { children:routes } = this.props
const { location } = this.state Sorry for being dense earlier! |
Nailed it, @taurose. Thanks :) |
@mjackson Can we get a release for this one? |
@wmertens Just released this morning in beta 7 |
I am now running beta7 but I'm still seeing my component being remounted. Any quick tips to find the responsible parent? |
@wmertens it's probably re-rendering due to props change on route change, not re-mounting. I can confirm there is no bug in beta 7. Thank you, guys! 👍 |
No, the constructor is getting called, and I have to figure out which
parent is responsible…
…On Sat, Mar 4, 2017, 9:14 AM Vlad Shcherbin ***@***.***> wrote:
I can confirm there is no bug in beta 7.
@wmertens <https://github.com/wmertens> it's probably re-rendering due to
props change on route change, not re-mounting.
Thank you, guys! 👍
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4578 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AADWllyPAsyLz-0UGy2rvcw6Hx6uRKEUks5riR1ngaJpZM4MIqcN>
.
|
Found it in code of my own (merge mishap). All I had to do was put a breakpoint in Reacts mountComponent: function (transaction, hostParent, hostContainerInfo, context) {
[...]
// Initialize the public class
var doConstruct = shouldConstruct(Component);
/*=> here*/ var inst = this._constructComponent(doConstruct, publicProps, publicContext, updateQueue); |
I am a bit new to React & React-Router. I am creating a SPA where I do not want components to be unmounted when I switch b/w routes. I am using 4.1.2 version of React-Router but ComponentDidMount is being called every time when I return to a mounted component after switching the route. Could you please suggest the version I should use. |
Try looking at the unmount/remounts via the timeline as explained in
https://facebook.github.io/react/blog/2016/11/16/react-v15.4.0.html - see
which component stays mounted, that is the one responsible for remounting
the rest
…On Fri, Aug 11, 2017 at 12:28 PM VaishaliJain0209 ***@***.***> wrote:
I am a bit new to React & React-Router. I am creating a SPA where I do not
want components to be unmounted when I switch b/w routes. I am using 4.1.2
version of React-Router but ComponentDidMount is being called every time
when I return to a mounted component after switching the route. Could you
please suggest the version I should use.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4578 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AADWlmbpq8woeyih0jKG216HY5bcUhRIks5sXCzCgaJpZM4MIqcN>
.
|
This still seems to be a problem if So this doesn't cause a re-mount:
But this does:
Is that intentional/am I missing something? |
What happens if you don't pass a key, or pass the same key twice?
And what are the circumstances of the remounting?
…On Thu, Aug 17, 2017 at 8:26 PM Katie Peters ***@***.***> wrote:
This still seems to be a problem if Switch is given an array of Route
components (because of the key prop?).
So this doesn't cause a re-mount:
<Switch>
<Route
component={App}
exact
path="/"
/>
<Route
component={App}
exact
path="/other"
/>
</Switch>
But this does:
<Switch>
{[
<Route
component={App}
exact
key="1"
path="/"
/>,
<Route
component={App}
exact
key="2"
path="/other"
/>,
]}
</Switch>
Is that intentional/am I missing something?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4578 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AADWlo8e0jneofN5jNBumYcZDtlf8iGuks5sZIXkgaJpZM4MIqcN>
.
|
@katiepeters Yes, React's reconciler will always unmount the existing component and mount a new one when two element's Edit Woops, I slightly misspoke. This behavior is not actually caused by the reconciler directly. This is the function that determines whether to update the existing component or unmount/mount: https://github.com/facebook/react/blob/master/src/renderers/shared/shared/shouldUpdateReactComponent.js#L25-L43 |
Ya, I ended up passing them the same key to get it to work. Wasn't sure if that was ideal, but maybe it's ok since |
I'm not sure, this commit fixed the bug, I upgraded the latest version v4.2.0 as your release, and try it, the component also remount. Here is my layout: const Layout = ({children, location}) => {
// url like /:personId/a, /:personId/b
const personId = location.pathname.split('/')[2]
// b or a path
const activeKey = location.pathname.split('/')[3]
// The problem is every time the path changed, the Profile always componentDidMount.
return <div>
<Profile personId={personId}/>
<Tabs
type="card"
activeKey={location.pathname.split('/')[3]}
onTabClick={(key) => {
const paths = location.pathname.split('/')
history.push(`/person/${personId}/${key}`)
}}
>
{tabs.map(tab =>
(<TabPane tab={tab.title} key={tab.key}>
{children}
</TabPane>),
)}
</Tabs>
</div>
} The below is the Router config: const routes = [
{
path: '/a',
component: A,
},
{
path: '/b',
component: B,
},
{
path: '/c',
component: C,
},
]
const Router = ({ match }) => (
<Switch>
{
routes.map(({ path, exact, strict, component: Comp }) =>
(<Route
key={path}
path={`${match.url}${path}`}
exact={exact}
strict={strict}
render={
props => (
<Layout {...props}>
<Comp {...props} />
</Layout>
)
}
/>),
)
}
</Switch>
) Every time the path change, the component will didMount again, so maybe my usage is the incorrect way to reuse the layout? |
I am causing the same problem. Any updates to this ?
This code will causes always a remount (not update of Component - I am talking about a remount) so everytime the url changed the componentWillMount get fired. |
@TimoRuetten that is very weird, can you share your whole code? This one looks too simplified… |
@wmertens Yeah - its a bit simplified - but at the end not that much. This is the current code of our
Then we have in our edit Using version 4.2.0 |
Are you sure it's the Switch and not something higher up? You can also put |
Hey @wmertens - You were right, I'm sorry. A HOC of my |
@KaroseLiu you should give your Routes all the same key… |
I still seem to be getting this issue ( class T extends Component {
componentWillUnmount() {
console.log("unmounting")
}
render() {
return null
}
}
...
<BrowserRouter>
<div>
<Switch>
<Route path="/a" key="1" /*or no key*/ children={() => <T />}
</Switch>
</div>
</BrowserRouter> Updating the path results in |
This snippet works as expected without any unnecessary remounts, so the problem must be somewhere else. |
for anyone searching here, I am not getting remounts on switch, UNLESS switch is wrapped with react transition group's TransitionGroup/CSSTransition components. correction, I believe my above comment is only an issue when passing a location to switch, which react transition group requires. It seems animating a switch with react transition group requires a location for the switch component, which in turn is causing a remount on the route's called component. |
You can also forego the switch and make sure only one route matches at a
time…
…On Wed, Oct 11, 2017, 6:32 PM Noah Mason ***@***.***> wrote:
correction, I believe my above comment is only an issue when passing a key
to switch, which react transition group requires.
Itb seems animating a switch with react transition group requires a
location for the switch component, which intern is causing a remount on the
routes called component.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4578 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AADWlgvDvEf1g5Ee6rgh2phKLBzS_PPYks5srO2OgaJpZM4MIqcN>
.
|
Version
4.0.0-beta.6
Test Case
Same issue as described here, the test case is from it
bug exists
http://codepen.io/ReactJSTraining/pen/ZLggog
no bug, but uses non-supported array as Route path
http://codepen.io/anon/pen/qReegR
Steps to reproduce
UsersIndex
component is the one, that is persistent across the routes. Change the route to reproduce the bug (this component is re-mounted).Expected Behavior
When route is changed,
UsersIndex
component is not re-mounted, only passed props are changing.Actual Behavior
When route is changed,
UsersIndex
component is re-mounted on every route change.This could be solved with Route path array support or current
Switch
component fix.The text was updated successfully, but these errors were encountered: