11

I am using react-router in my application and I am looking for a way to stop the remount of components that are already in the DOM. For example, if I am at the URL dashboard, then I will have an associated DashboardComponent mounted. When I transition to dashboard/settings then my DashboardComponent as well as SettingsComponent get remounted into the DOM. I would like to find a clean way to mount only the children of the current URL. Is this posible?

Router:

import { Component, createFactory, PropTypes } from 'react'
import { Route, RouteHandler, DefaultRoute, NotFoundRoute } from 'react-router'

import Home from '../components/Home'
import Dashboard from '../components/Dashboard'
import ViewPlayers from '../components/clubs/ViewPlayers'

let route = createFactory(Route),
    handler = createFactory(RouteHandler),
    root = createFactory(DefaultRoute),
    pageNotFound = createFactory(NotFoundRoute),
    Transitions = createFactory(require('react/lib/ReactCSSTransitionGroup'));

class App extends Component {

    constructor() {

        super();
    }

    render() {

        return (
            Transitions({transitionName: 'fade'},
                handler({key: this.context.router.getCurrentPath()})
            )
        )
    }
}
App.contextTypes = {
    router: PropTypes.func
};

let Router = (
    route({path: '/', name: 'home', handler: App},
        root({handler: Home}),
        route({path: 'dashboard', name: 'dashboard', handler: Dashboard},
            route({path: 'players', name: 'players', handler: ViewPlayers}),
        )
    )
);
export { Router };

Dashboard (Parent component):

import React from 'react'
import { RouteHandler, Link } from 'react-router'
import { _, div } from './Html'

export default
class Dashboard extends React.Component {

    constructor() {

        super();

        this.state = {}
    }

    componentWillMount() {

        console.log('mounted')
    }

    componentWillUnmount() {

    }

    render() {

        return (
            div({},
                _(Link)({to: 'players'}),
                _(RouteHandler)({})
            )
        )
    }
}

Note: _ is just a wrapper for React.createFactory()

Julien Vincent
  • 1,210
  • 3
  • 17
  • 40
  • What version of React Router are you using? AFAIK the normal behavior is to just let React do it's reconciliation algorithm, which by default will not remount components in the tree that don't change type or position. It will *re-render* the components, but shouldn't re-mount them. – Michelle Tilley Aug 04 '15 at 17:50
  • Perhaps my understanding about how react does it's render is incorrect, but on transition change, `componentWillMount` is fired - does this not indicate that the component is remounting? I am using `v 0.13` – Julien Vincent Aug 04 '15 at 17:59
  • Yes, that indicates the component is remounting, but I double-checked on one if my own React Router v0.13 projects, and as long as the component stays the same and in the same position in the tree, it doesn't re-mount. Do you have some code or a reproducible example you can share? – Michelle Tilley Aug 04 '15 at 18:05

1 Answers1

58

React always unmounts and remounts components when its key changes—that's the purpose of that property, to help React maintain an "identity" of a component. In particular, it's required when using React's CSS transitions, because the only way to animate out one component and animate in another is to have them be separate DOM nodes.

Because you pass {key: this.context.router.getCurrentPath()} to the handler component inside App, React will unmount and remount the handler component, even if it's the same type, any time getCurrentPath() returns a different value. The solution would be to find a key that changes when you do want to animate, but stays the same otherwise.

Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • 1
    brilliant. I set the key to `location.href`, works perfectly –  Apr 24 '18 at 06:00
  • 1
    I can't believe that I didn't think of this – I'm an experienced React dev and have only used key in `.map()`s before – this approach of telling React "this thing is completely new" is a game-changer for me. – shankie_san Jun 09 '20 at 13:27