WebReflection / hyperHTML

A Fast & Light Virtual DOM Alternative
ISC License
3.07k stars 112 forks source link

wires in the middle of a list always re-render #67

Closed joshgillies closed 7 years ago

joshgillies commented 7 years ago

Sorry for the awkward issue title, I wasn't entirely sure how to describe it best. Feel free to update if there's something more appropriate.

Anyways, for this I feel like the code speaks for itself. In the following example the hyperHTML.wire(model, ':ul') wire, will always re-render.

import hyperHTML from 'hyperhtml'

function render (model) {
  return hyperHTML.wire(model)`
    <div>
      <h1>Heading</h1>${hyperHTML.wire(model, ':ul')`
      <ul>${
        model.links.map((link) => hyperHTML.wire(link)`
        <li>
          <a href="${link.href}"> ${link.text} </a>
        </li>`)
      }</ul>`
      }<div>
        ${model.content}
      </div>
    </div>
  `
}

const model = {
  links: [
    {
      text: 'Link 1',
      href: '#link1'
    },
    {
      text: 'Link 2',
      href: '#link2'
    }
  ],
  content: 'Static content'
}

hyperHTML.bind(document.body)`${render(model)}`

setTimeout(render, 5000, model)

Note the above yields the expected results (no re-rendering of any node) if hyperHTML.wire(model, ':ul') is wrapped in a parent node, eg. <div>hyperHTML.wire(model, ':ul')...</div>.

WebReflection commented 7 years ago

TL;DR 0.15.3 fixes this


The node wasn't re-rendered, simply re-appended.

This was caused by different handling of single virtual node, a situation where you have a node in between others instead of as content (the faster and more common any node case).

However, the logic should've been the same used for an array of nodes, but it wasn't.

0.15.3 now uses exact same logic resulting in actually slightly smaller final size and consistent results :tada:

Thanks for filing the bug.

joshgillies commented 7 years ago

Awesome, really impressive work @WebReflection 👌