Page 1 of 2 12 LastLast
Results 1 to 10 of 12

Thread: React component lifecycle method componentWillUnmount is not called by ExtJS

    Success! Looks like we've fixed this one. According to our records the fix was applied for REAC-146 in 1.1.0.
  1. #1
    Sencha User
    Join Date
    May 2017
    Posts
    68

    Default React component lifecycle method componentWillUnmount is not called by ExtJS

    When you make one of the native React components a child of the ExtReact React component, the native React component's componentWillUnmount will never be called potentially resulting in memory and resource leaks as well as other side effects.

    I have the following sample layout:

    HTML Code:
    <App>
       <BrowserRouter>
          <Container>
             <Transition>
                 <Switch>
                    <Route path="/1" component={Test1} />
                    <Route path="/2" component={Test2} />
                 </Switch>
            </Transition>
         </Container>
    </App>
    Test1 renders this:
    HTML Code:
    <Container>
        <SomeReactComponentWithLifecycleMethods1 />
    </Container>
    Test2 renders this:
    HTML Code:
    <Container>
        <SomeReactComponentWithLifecycleMethods2 />
    </Container>
    SomeReactComponentWithLifecycleMethods1 and SomeReactComponentWithLifecycleMethods2 components have both componentWillMount and componentWillUnmount methods. When you switch a route from /1 -> /2 -> /1, etc. only componentWillMount is ever called. componentWillUnmount is never called.

    The problem seems to be in the ExtJSComponent.unmountComponent where child components are not iterated and their lifecycle methods are not called is never called.



    Thank you,
    Yuri

  2. #2
    Sencha User
    Join Date
    May 2017
    Posts
    68

    Default

    I found a fix.

    All you have to do is modify your ExtJSComponent.unmountComponent (changes are in bold):

    Code:
     
    unmountComponent(safely) {
        if (this.cmp) {
            if (this.cmp.destroying || this.cmp.$reactorConfig) return;
    
            this.unmountChildren(safely);
    
            const parentCmp = this.cmp.ownerCt /* classic */ || this.cmp.getParent(); /* modern */
    
            // remember the parent and position in parent for dangerouslyReplaceNodeWithMarkup
            // this not needed in fiber
            let indexInParent;
    
            if (parentCmp) {
                if (parentCmp.indexOf) {
                  // modern
                  indexInParent = parentCmp.indexOf(this.cmp);
                } else if (parentCmp.items && parentCmp.items.indexOf) {
                  // classic
                  indexInParent = parentCmp.items.indexOf(this.cmp);
                }
            }
    
            if (this.reactorSettings.debug) console.log('destroy', this.cmp.$className);
    
            if (Ext.navigation && Ext.navigation.View && parentCmp && parentCmp instanceof Ext.navigation.View) {
                parentCmp.pop();
            } else {
                 this.cmp.destroy();
            }
    
            // remember the parent and position in parent for dangerouslyReplaceNodeWithMarkup
            // this not needed in fiber
            this.el._extIndexInParent = indexInParent;
            this.el._extParent = parentCmp;
        }
    }
    

  3. #3
    Sencha User
    Join Date
    Mar 2015
    Location
    Maryland
    Posts
    482

    Default

    I'm not about to reproduce this. I added a componentWillUnmount() method to the About component in reactor-boilerplate and it gets called as expected. Here is my code:

    Code:
    import React from 'react';
    import { Container } from '@extjs/ext-react';
    
    
    export default class About extends React.Component {
    
    
        componentWillUnmount() {
            console.log('Unmount about');
        }
    
    
        render() {
            return (
                <Container padding="20">
                    <h1>About this App</h1>
                    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam eget leo sed mi imperdiet dictum a id turpis. Suspendisse a ante eu lorem lacinia vestibulum. Suspendisse volutpat malesuada ante, sed fermentum massa auctor in. Praesent semper sodales feugiat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris mauris ante, suscipit id metus non, venenatis tempor tortor. In ornare tempor ipsum. Sed rhoncus augue urna, ut dapibus odio fringilla vitae. Phasellus malesuada mauris ut nulla varius sodales. Sed et leo luctus, venenatis felis sit amet, vehicula nibh. Curabitur fringilla fringilla nibh, porttitor lacinia urna vestibulum eu. Integer ac aliquet risus. Curabitur imperdiet quis purus at consectetur. Sed ornare vitae felis a scelerisque. Donec mi purus, auctor sit amet molestie nec, imperdiet auctor mauris.</p>
                </Container>
            )
    
    
        }
    }

  4. #4
    Sencha User
    Join Date
    May 2017
    Posts
    68

    Default

    As I said, You have to make the component reside under ExtJS component. Put a native React component (with componentWillUnmount) directly under Container and you will see it.

    The reason it works in your case is that About is a direct child of the Route component and it does not have any ExtJSComponent-based anscestor. But anything you put under Container (ExtJSComponent) will not be properly cleaned up.

    I'm actually quite surprised that it made it into the release as lifecycle methods are a bread-and-butter of React.

  5. #5
    Sencha User
    Join Date
    Mar 2015
    Location
    Maryland
    Posts
    482

    Default

    Yep you're totally right. Sorry, I didn't see the fix you posted until just now. I arrived at the same one without seeing it so it must be right Let me do some testing first and I'll push out a prerelease shortly.

  6. #6
    Sencha User
    Join Date
    Mar 2015
    Location
    Maryland
    Posts
    482

    Default

    Good news: that also seems to fix the bug with componentWillUnmount not being called on components rendered by Templates. Thank you for helping with this!

  7. #7
    Sencha User
    Join Date
    May 2017
    Posts
    68

    Default

    Actually, it should not. The template uses ReactDOM.render which renders it into an independent subtree.

    So technically, it is not part of the pipeline. Try to use it with a paged grid and see if it is called when the new page is rendered.

  8. #8
    Sencha User
    Join Date
    May 2017
    Posts
    68

    Default

    Just confirmed that componentWillUnmount is not called when a component is embedded in the template and the template goes out of scope. This is expected as ReactDOM.render renders into an independent DOM tree so the upstream React pipelines do not know anything about it. Plus, Facebook docs explicitly say that you have to call unmountComponentFromNode to do that:

    https://facebook.github.io/react/doc...omponentatnode

  9. #9
    Sencha User
    Join Date
    May 2017
    Posts
    68

    Default

    And I also noticed that in your POC implementation of the ExtJSRenderer for fiber you do not call ReactDOM.unmountComponentFromNode either.

  10. #10
    Sencha User
    Join Date
    Mar 2015
    Location
    Maryland
    Posts
    482

    Default

    Thanks for the report! I have opened a bug in our bug tracker.

Page 1 of 2 12 LastLast

Similar Threads

  1. [OPEN] afterErase method in Ext.Component is never called after model is destroyed
    By debianw in forum Sencha Touch 2.x: Bugs
    Replies: 2
    Last Post: 26 Feb 2014, 11:56 AM
  2. Method must be called after the component is rendered
    By kpb in forum Ext GWT: Discussion
    Replies: 4
    Last Post: 14 May 2010, 2:10 PM
  3. Replies: 6
    Last Post: 29 Jul 2009, 2:58 PM
  4. Help With Example -Method must be called before the component is rendered
    By Manuel Elaraj in forum Ext GWT: Help & Discussion (1.x)
    Replies: 4
    Last Post: 17 Jun 2009, 7:04 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •