Is it possible to only remount only the new child components on react-router transition
Asked Answered
C

1

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()

Caterpillar answered 4/8, 2015 at 15:36 Comment(3)
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.Nedanedda
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.13Caterpillar
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?Nedanedda
N
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.

Nedanedda answered 4/8, 2015 at 18:16 Comment(2)
brilliant. I set the key to location.href, works perfectlyUrbane
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.Evora

© 2022 - 2024 — McMap. All rights reserved.