question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Unmount not called for nested children on render (since preact X)

See original GitHub issue

I encountered a behaviour, that I think can be considered a bug, unless it was intentionally introduced with preact X.

This is a common way to force unmount of components in a specific container:

render(<div />, container, container.firstElementChild)

Using this on the following HTML with preact 8, results in componentWillUnmount of the component being properly called. (Note that the component can be as deeply nested inside the container as wished)

<div id="container">
  <div>
    <MyComponent />
  </div>
</div>

With preact X however, the component is not unmounted, which is really bad for my understanding. There now is no way, that I know of, to achieve emptying a container and properly unmouting all components inside. This is specifically bad for single page applications, like mine, that do this frequently.

If the component is not nested, but a direct child of the container, it even works with preact X.

<div id="container">
  <MyComponent />
</div>

Here I have two exactly similar codepens showing this behaviour, only different in the preact version. One runs with 8.5.2 and one with 10.0.5.

preact 8: https://codepen.io/timonwitt/pen/NWPqwxO preact X: https://codepen.io/timonwitt/pen/BayNwzW

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:8
  • Comments:26 (19 by maintainers)

github_iconTop GitHub Comments

2reactions
timon-wittcommented, Jan 9, 2020

For everyone searching for a working solution, here is how we finally implemented it on our side. Checking for __k property on every single dom element is not really practicable from a performance perspective.

Basically have an enhanced wrapping render function, that marks preact root elements with an attribute. These can then be identified fast and unmounted.

/**
 * Preact containers, that are rendered with the render function below, receive this attribute.
 * It is used to identify preact containers afterwards.
 */
const preactContainerAttr = 'data-preact-container';

/**
 * Enhanced preact.render function.
 */
export const render: typeof preact.render = (vnode, parent, replaceNode): void => {
  if (parent instanceof Element) {
    parent.setAttribute(preactContainerAttr, 'true');
  }
  preact.render(vnode, parent, replaceNode);
};

/**
 * Unmounts all preact components inside the given element and its children.
 * @param parent Pass the parent here, where the component is rendered into.
 *               Don't pass a component itself.
 */
export const unmount = (parent: Element): void => {
  let parentsToUnmount = [];

  // Check the passed element itself.
  if (parent.getAttribute(preactContainerAttr) === 'true') {
    parentsToUnmount.push(parent);
  }

  // Check child elements
  parentsToUnmount.push(...Array.from(
    parent.querySelectorAll(`[${preactContainerAttr}=true]`)
  ));

  // Execute unmount
  parentsToUnmount.forEach(container => {
    preact.render(null, container);
    container.removeAttribute(preactContainerAttr);
  });
};
1reaction
marvinhagemeistercommented, Dec 20, 2019

Changing the handling of the way we treat roots has come up a few times in the past weeks. The main interest is to set markers for lazy hydration. Because of that we haven’t made any part surrounding roots public. My guess is that it will remain private (and thus mangled) until we settle on something we can commit ourselves to make public and take on maintenance. But that may be months away.

For now your best bet is to rely on the private mangle property. Due to our build pipeline you can be sure that the mangled name won’t change across Preact versions, so there is at least a little bit of guarantee there.

Read more comments on GitHub >

github_iconTop Results From Across the Web

componentWillUnmount() not being called when refreshing ...
I need the componentWillUnmount() to be called when refreshing the page because in my componentWillMount() function (which needs to re-render after every ...
Read more >
API Reference | Preact: Fast 3kb React alternative with the ...
The render() function is required for all components. It can inspect the props and state of the component, and should return a Preact...
Read more >
A Semantics for the Essence of React - DROPS
to render Component all we would see would be a h1 tag. In React, nested component descriptors are simply treated as a special...
Read more >
Preact - Releases
This hook creates stable unique identifiers that are consistent between server-side rendering (using preact-render-to-string) and client-side hydration.
Read more >
A Semantics for the Essence of React - Frank Tip
to render Component all we would see would be a h1 tag. In React, nested component descriptors are simply treated as a special...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found