Conditional rendering in hyper.Component not updating DOM

308 Views Asked by At

I wonder why following snippet is not updating DOM

    const { hyper, wire } = hyperHTML;

    class Input extends hyper.Component {
      get defaultState() {
        return { error: false };
      }
      onclick() {
        this.setState(prev => ({ error: !prev.error }));
      }

      render() {

        const textField = wire()
        `
          <div onconnected=${this} ondisconnected=${this}>
            <input type="text" value="foo" onclick=${this}>
            <label>bar</label>
          </div>
          `;


        let finalNode;
        if (this.state.error) {

          finalNode = this.html `
            <div>
              ${textField}
              <p>
                some name
              </p>
            </div>
            `;

        } else {
          finalNode = this.html `
            <div>
              ${textField}
            </div>
            `;
        }
        return finalNode;
      }
    }


    document
      .getElementById('root')
      .appendChild(new Input().render());

I would expect it would it to render textField first and upon click to render p element along. I can see that render call is made but resulting element does not end up in DOM.

1

There are 1 best solutions below

0
On BEST ANSWER

With hyper.Component the best way to go is to make the content conditional, not the root as a whole.

In order to do that, you can simply use a ternary, or an array.concat(...) or any other way that will update the component.

It's like the difference between updating an instance and replacing it. From the inside, the component has no power to replace itself on its parent, unless you explicitly do so.

However, this example is easier than it looks like, and you can see it working on this Code Pen.

Moreover, if you don't specify onconnected and ondisconnected callbacks in the class, there's no need to specify them on the node.

const { hyper, wire } = hyperHTML;

class Input extends hyper.Component {

  get defaultState() { return { error: false }; }

  onclick() {
    this.setState(prev => ({ error: !prev.error }));
  }

  render() { return this.html`
    <div>
      <div>
        <input type="text" value="foo" onclick=${this}>
        <label>bar</label>
      </div>
      ${this.state.error ?
        wire(this, ':extra')
        `<p> some name </p>` :
        null
      }
    </div>`;
  }
}

document.body.appendChild(new Input().render());

I hope this helped.