Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inconsistent or duplicate elements rendered when using preact standalone version #159

Closed
catdad opened this issue Mar 15, 2020 · 2 comments · Fixed by #163
Closed

inconsistent or duplicate elements rendered when using preact standalone version #159

catdad opened this issue Mar 15, 2020 · 2 comments · Fixed by #163

Comments

@catdad
Copy link

catdad commented Mar 15, 2020

I created a small repro demo that I set up in two ways:

  • using preact@10.3.4 with htm@3.0.3
  • using only htm@3.0.3 with the preact standalone version of the module

Code:

//import { html, render } from 'https://cdn.jsdelivr.net/npm/htm@3.0.3/preact/standalone.module.js';
//import { Fragment } from 'https://cdn.jsdelivr.net/npm/preact@10.3.4/dist/preact.module.js';

import { h, render, Fragment } from 'https://cdn.jsdelivr.net/npm/preact@10.3.4/dist/preact.module.js';
import htm from 'https://cdn.jsdelivr.net/npm/htm@3.0.3/dist/htm.module.js';
const html = htm.bind(h);

const elem = document.querySelector("#app");

const Item = (item) => {
	return html`
  	<div key=${item.id} data-id=${item.id}>
      ${item.text}
    </div>`;
};

const items = [{id: 1, text: 'one'}, { id: 2, text:'two' }];

const performRender = () => {
  const children = items.map(item => html`<${Item} ...${item} />`);
  render(html`<${Fragment}>${children.reverse()}<//>`, elem);
};

setTimeout(() => {
  items.push({ id: 3, text: 'three'});
  performRender();
}, 1000);

setTimeout(() => {
  items.push({ id: 4, text: 'four'});
  performRender();
}, 2000);

window.onload = performRender;

Fiddle for reference: https://jsfiddle.net/0ukweoz1/2/

Results:

  • when using preact with htm, the final version renders as:
four
three
two
one
  • using htm preact standalone, the final version renders as:
four
three
two
one
one

note that also, the render after 1 second does not actually update the DOM, so three is never just added by itself

@developit
Copy link
Owner

Hi @catdad - this happens because you are using two copies of Preact - Fragment from one, and render() from another. Preact is a singleton and using two copies of it will cause all sorts of strange problems like this, in addition to just downloading preact twice.

Some context - the reason we don't export Fragment from htm/preact/standalone is because it should never be necessary when using HTM, since HTM supports implicit fragments.

However: it looks like the copy of Preact we bundled with htm 3.0.3 has a bug with fragments at the root, or our bundling is breaking something. That's a bug.

Here's your demo without the Fragment usage:

// should work, but seems to have an issue with bundled preact and fragments:
//import { html, render } from 'https://cdn.jsdelivr.net/npm/htm@3.0.3/preact/standalone.module.js';

import { h, render } from 'https://cdn.jsdelivr.net/npm/preact@10.3.4/dist/preact.module.js';
import htm from 'https://cdn.jsdelivr.net/npm/htm@3.0.3/dist/htm.module.js';
const html = htm.bind(h);

const elem = document.querySelector("#app");

const Item = (item) => {
	return html`
  	<div key=${item.id} data-id=${item.id}>
      ${item.text}
    </div>`;
};

const items = [{id: 1, text: 'one'}, { id: 2, text:'two' }];

const performRender = () => {
  const children = items.map(item => html`<${Item} ...${item} />`);
  render(html`${children.reverse()}`, elem);
};

setTimeout(() => {
  items.push({ id: 3, text: 'three'});
  performRender();
}, 1000);

setTimeout(() => {
  items.push({ id: 4, text: 'four'});
  performRender();
}, 2000);

window.onload = performRender;

@developit
Copy link
Owner

This has been fixed! It's available on unpkg and npm as htm 3.0.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants