WebReflection / hyperHTML

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

Conditional rendering and onconnected/ondisconnected events #325

Closed lmgonzalves closed 5 years ago

lmgonzalves commented 5 years ago

First of all, thank you so much for this amazing project!

The issue I'm having is with conditional rendering basically. I've created a minimal working example: https://codepen.io/lmgonzalves/pen/zyawML

But here is the render function to provide some context:

hyperHTML.bind(document.body)`
  <button onclick="${increment}">Increment</button>
  <p>${m}</p>
  <p>Hide "<span>TEST</span>" only if the number is divisible by 3</p>
  ${m % 3 ? hyperHTML.wire()`
    <p onconnected="${onconnected}" ondisconnected="${ondisconnected}">
      <span>TEST</span>
    </p>
  ` : ''}
`

When I click the button, the counter increments, and if it is divisible by 3, it hides the TEST message.

I have 2 issues actually:

  1. I'm listening to onconnected and ondisconnected events, but those events are triggered even when the TEST message don't need to be modified. Is it a way to have conditional rendering without disconnecting and connecting elements unnecessarily?

  2. The onconnected event is always triggered first. So, if the element is already connected, it dispatch the onconnected event first, and then dispatch the ondisconnected event. It should happen in reverse order, right?

Thanks!

joshgillies commented 5 years ago

Basically, within your render function, you're creating a new wire hyperHTML.wire() every time it's called. Which in turn creates a new set of DOM nodes with new connected/disconnected handers.

To avoid this, you must pass a unique object as the first argument to hyperHTML.wire(). Given your example the following works as expected.

Note: hyperHTML.wire(render)

function render () {
  console.log('render!')

  hyperHTML.bind(document.body)`
    <button onclick="${increment}">Increment</button>
    <p>${m}</p>
    <p>Hide "<span>TEST</span>" only if the number is divisible by 3</p>
    ${m % 3 ? hyperHTML.wire(render)`
      <p onconnected="${onconnected}" ondisconnected="${ondisconnected}">
        <span>TEST</span>
      </p>
    ` : ''}
  `
}
WebReflection commented 5 years ago

Yup, like @joshgillies said, you need a reference to obtain same node from a wired template.

Alternatively, instead of the function itself, you could wire the parent node itself and use a unique id:

function render () {
  console.log('render');

  const {body} = document;
  hyperHTML.bind(body)`
    <button onclick="${increment}">Increment</button>
    <p>${m}</p>
    <p>Hide "<span>TEST</span>" only if the number is divisible by 3</p>
    ${m % 3 ? hyperHTML.wire(body, ':conditional')`
      <p onconnected="${onconnected}" ondisconnected="${ondisconnected}">
        <span>TEST</span>
      </p>
    ` : ''}
  `
}
lmgonzalves commented 5 years ago

Thank you both!