preact icon indicating copy to clipboard operation
preact copied to clipboard

Components added lazily in componentDidMount is removed on re-render of parent component

Open cw-shivanisanyal opened this issue 8 years ago • 2 comments
trafficstars

I have recently decided to replace React with Preact on my existing web application. I'm testing my application for any breaking changes. I have found the following which works well in React but behaves differently when using Preact.

I have a parent component App with a render function as follows. Components are lazily added inside the div with id "peripheralComponents" using webpack functionality require.ensure in componentDidMount of component App. The code is as follows:

class App extends React.Component {
    componentDidMount() {
        LoadPeripheralComponents().then((PeripheralComponents) => {
           render(
                <div>
                    <PeripheralComponents.GlobalCityPopup/>
                    <PeripheralComponents.GlobalSearchPopup/>
                </div> , document.getElementById ( 'peripheralComponents' )
            )

        })
    }
    render() {
        return (
            <div>
                <div className="body-content">
                    <Switch>
                        <Route exact path='/m/news/' component={NewsArticleListContainer}/>
                        <Route exact path='/m/news/page/:pageNo/' component={NewsArticleListContainer}/>
                    </Switch>
                </div>
                <div id="peripheralComponents">
                </div>
            </div>
        )
	}
}

LoadPeripheralComponents function is defined as follows:

export default () => {  
    return new Promise(resolve => {
        require.ensure([], function(require){
            var GlobalCityPopup = require('../components/GlobalCityPopup');
            var GlobalSearchPopup = require('../components/GlobalSearchPopup');
            resolve({
                GlobalCityPopup: GlobalCityPopup,
                GlobalSearchPopup : GlobalSearchPopup,
            });
        }, "peripheralComponents");
    });
};

Component GlobalCityPopup has "style.display = none" by default. On clicking a button, the following code is executed which adds a hash and changes the CSS of GlobalCityPopup to make it visible

function openGlobalCityPopUp() {
      document.getElementById('globalcity-popup').style.display = 'block';
      window.location.hash = "globalCity";
 }

Adding the hash value causes re-render of the parent component App causing the lazily added components in div with id peripheralComponents to be removed and returning an empty div.

While using React and the same implementation, the lazily added components persisted. Is this due to a different diffing algorithm followed by Preact, as compared to React? What should be the process to persist components added anywhere other than the render function?

cw-shivanisanyal avatar Jul 12 '17 13:07 cw-shivanisanyal

This is because preact doesn't currently know about its own render roots, so the outer component tree continues diffing the inner one. We'll need to add a property at the root of a Preact tree indicating that it's a different render.

developit avatar Jul 17 '17 02:07 developit

This is because preact doesn't currently know about its own render roots

What do you mean by this statement?

We'll need to add a property at the root of a Preact tree indicating that it's a different render.

And how do I do this? Is there a default parameter that can be used to specify this?

cw-shivanisanyal avatar Jul 17 '17 05:07 cw-shivanisanyal