snabbdom / snabbdom

A virtual DOM library with focus on simplicity, modularity, powerful features and performance.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Snabbdom removes `null`, causing unsafe reuse of elements

cjohansen opened this issue · comments

It seems that Snabbdom removes null from the list of children prior to patching the DOM. This causes Snabbdom to consider elements that are not logically "the same element" to actually be the same, and unsafely reuses the DOM element.

An example follows:

var patch = snabbdom.init([
  snabbdom.styleModule
]);

var el = document.createElement('div');
document.body.appendChild(el);

var h = snabbdom.h;

vdom = patch(el,
             h('div', {}, [
               null,
               h('div', {}, ['Snabbdom'])
             ]));

setTimeout(function () {
  vdom = patch(vdom, h('div', {}, [
    h('div', {style: {
      opacity: 0.3,
      transition: "opacity 0.5s"}}, ['Hello']),
    h('div', {}, ['Snabbdom'])
  ]));
}, 2000);

When this first renders, it says "Snabbdom". After 2 seconds, it will say "Hello Snabbdom". The peculiar thing is that the "Hello" has its opacity animated from 1 to 0.3. This breaks with my expectation: I was expecting the DOM node to be inserted with a "starting opacity" of 0.3, and then apply transitions to any upcoming changes. This is indeed what happens if you recreate this example with React (the code where this was discovered was ported from React to Snabbdom).

Because Snabbdom has removed the null from the first render, it considers the initial "Snabbdom" element to be same as the "Hello" element in the update. Thus, when the element is being reused, the transition is carried out.

This problem can be manually side-stepped by using a key on the element, but it shouldn't be necessary, as Snabbdom can just use the element's position to know that reusing the DOM element in this case is not safe. But in order to do that, it must keep on to the null for longer than it currently does.

For now I've worked around this in dumdom by generating comment nodes in place of nulls, but that should in my opinion not be necessary.