Preact: ComponentWillUnmount throwing error, when refering to a DOM node

Created on 19 Jun 2017  路  1Comment  路  Source: preactjs/preact

Description

1.

When a component is replaced with another one, the DOM is updated, before the componentWillUnmount event is called. This prevents the execution of scripts, depending on the DOM Elements of the component.

I created an example. When you change from the Home tab to another one, you should get an alert, with the result of the shown query. Inside the console, I log the trace of the call.

2.

Additionally the componentWillUnmount is iterated in a top-down approach, so if a child of a component has a componentWillUnmount set, it's fired, when the containing component is already removed, resulting in the same error.

This example already contains the fix for No. 1 and shows the problem of the nested component in the same way, as ex 1.

Expected behavior

componentWillUnmount should be called, before the DOM Nodes are removed.

Shown behavior

componentWillUnmount is called, after the DOM Nodes are removed.

Source of problem

1.

In vdom/component.js the child is replaced and after that replacement, 'componentWillUnmount' is called.

2.

In vdom/component.js the base node is removed and the the children are collected and removed.

Solution

1.

Change vdom/component.js to

if (baseParent && base!==baseParent) {

  baseParent.replaceChild(base, initialBase);

  if (!toUnmount) {
    initialBase._component = null;
    recollectNodeTree(initialBase, false);
  } else {
    baseParent.insertBefore(initialBase,base);
    unmountComponent(toUnmount);
    toUnmount = null;
   }
}

2.

The traversal of the DOM tree should be bottom top, while calling componentWillUnmount. After reaching the top node, which has to be removed, it could be removed without removing each child separately.

bug important

Most helpful comment

The code from the linked snippet would make a great test case:

class Foo extends Component {
    componentWillUnmount() {
      expect(document.getElementById("foo")).to.not.equal(null);
    }; 

    render() {
        return <div id="foo" />;
    }
}

render(<Foo />, scratch);
render(null, scratch);

>All comments

The code from the linked snippet would make a great test case:

class Foo extends Component {
    componentWillUnmount() {
      expect(document.getElementById("foo")).to.not.equal(null);
    }; 

    render() {
        return <div id="foo" />;
    }
}

render(<Foo />, scratch);
render(null, scratch);
Was this page helpful?
0 / 5 - 0 ratings

Related issues

marcosguti picture marcosguti  路  3Comments

kay-is picture kay-is  路  3Comments

philipwalton picture philipwalton  路  3Comments

jescalan picture jescalan  路  3Comments

youngwind picture youngwind  路  3Comments