Preact: `render` appends instead of replacing

Created on 27 Jan 2016  路  9Comments  路  Source: preactjs/preact

React: http://codepen.io/anon/pen/LGdaMd
Preact: http://codepen.io/anon/pen/GoxePz

Expected: print 2 on screen
Actual: prints 1 and 2 on screen

This prevents a correct comparison in the vdom benchmark because it causes the update benchmarks to measure the cost of full creation of a tree instead: http://vdom-benchmark.github.io/vdom-benchmark/

question

Most helpful comment

@mikestead Good call, thanks for leaving the note. If it's only a text or comment node and you're expecting an Element, you could also try node.firstElementChild (example). For picking up from SSR though, I think your solution is still the most robust.

All 9 comments

Hi Leo!

Preact's render is just a slight bit different in that regard, because it does not mark the DOM with data-attributes. Instead, render() accepts an optional third argument that is the root element to replace.

So, to emulate react's behavior just do:

render(<App />, into, into.lastChild);

I can look into making this the default since its an inconsistency. At the very least, its something that preact-compat should patch but does not currently.

Thanks!

Thanks for the fast response! I'll try that out

Is there any way to reuse element rendered on server side with preact-render-to-string?

The following code is appending second element becouse It's expecting component created by preact

var container = document.getElementById('container');
render(<App />, container, container.lastChild);

@kucharzyk: The code you pasted should work, so I investigated and found an issue. The fix is released in preact 2.8.2. Here is a simple demo:
http://codepen.io/developit/pen/adKzPj?editors=0010

Just in case any others trip up on this one, I was running into duplicates but it was down to node.firstChild returning a #text node due to white space, e.g.
http://codepen.io/anon/pen/bZxqRv?editors=1010

The solution was to target the child directly http://codepen.io/anon/pen/AXPqrk?editors=1010

Or simply strip the white space between parent and child elements if using firstChild.

@mikestead Good call, thanks for leaving the note. If it's only a text or comment node and you're expecting an Element, you could also try node.firstElementChild (example). For picking up from SSR though, I think your solution is still the most robust.

@developit Hi,
I'm using material-ui-next and .firstChild is causing trouble with menus as you can see here

const menuList = ReactDOM.findDOMNode(this.menuList);
    if (menuList && menuList.firstChild) {
      menuList.firstChild.focus();
    }
Menu.js:113 Uncaught (in promise) TypeError: menuList.firstChild.focus is not a function
    at Menu._this.focus (Menu.js:113)
    at Object.Menu._this.handleEnter [as onEnter] (Menu.js:121)
    at Object.Popover._this.handleEnter [as onEnter] (Popover.js:242)
    at Object.Grow._this.handleEnter [as onEnter] (Grow.js:119)
    at Transition.performEnter (Transition.js:242)
    at Transition.updateStatus (Transition.js:215)
    at Transition.componentDidMount (Transition.js:157)
    at flushMounts (preact.esm.js:328)
    at diff (preact.esm.js:357)
    at render (preact.esm.js:991)

Is there something I can do?
I'm using preact and precat-compat.
thanks!

You're accessing firstChild before the child has been added. Use a later lifecycle callback or wrap it in a timeout.

when using children[0] / firstElementChild everything works fine.
anyways, the issue is caused by material-ui - I don't have the liberty of changing it at this time.
Thanks anyways.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kossnocorp picture kossnocorp  路  3Comments

jasongerbes picture jasongerbes  路  3Comments

skaraman picture skaraman  路  3Comments

k15a picture k15a  路  3Comments

youngwind picture youngwind  路  3Comments