I'm new to Preact, so it's possible I'm missing something, but I'm noticing an issue with Preact that doesn't happen when using React. Here's my basic setup:
// index.js
import {h, render} from 'preact';
import App from './App.js';
function renderApp() {
render(<App />, document.querySelector('#root'));
}
// Initial render.
renderApp();
// App.js
import {h} from 'preact';
function App() {
return (
<div>
<h1>Hello World!</h1>
</div>
)
}
export default App;
This code works as expected, but if I change index.js to invoke renderApp() more than once, instead of replacing the root, it creates a new <App /> instance in root.
// index.js
// ...
// Initial render.
renderApp();
renderApp();
renderApp();

In case it's relevant, here's my Webpack 2 config and .babelrc
module.exports = {
devtool: 'cheap-module-source-map',
entry: [
'./src/index.js'
],
output: {
path: './build',
filename: 'bundle.js',
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: [/node_modules/]
},
],
}
};
{
"presets": [
["es2015", {"modules": false}],
"react"
],
"plugins": [
["transform-react-jsx", {"pragma":"h"}]
]
}
Let me know if you need any more info to reproduce this.
Also, FWIW, I discovered this issue when trying to get module hot reloading working with the following code:
if (module.hot) {
module.hot.accept('./App.js', renderApp);
}
Everything was working fine except the rerender, which was adding a new root as described above instead of replacing the old one.
Hi there! This is covered in What's Different but I'll summarize since it's come up before :)
Basically, preact's render() does not replace by default. This is because doing so would require guessing which element you intended to replace (since you only pass the parent). Instead, there is a third argument you can pass, which is the element to replace. In your case, you just need to keep a reference to the root element, which is returned from render(), and pass it back on the next call:
// index.js
import {h, render} from 'preact';
import App from './App.js';
let root;
function renderApp() {
root = render(<App />, document.querySelector('#root'), root);
}
// Initial render.
renderApp();
if (module.hot) {
module.hot.accept('./App.js', renderApp);
}
Also - just based on the querySelector all, you might be interested in knowing that preact is happy to render your app into <body>. Unlike React, there is no need to wrap everything in a div :)
Let me know if I didn't answer your question, or if we're all good and can close the issue out!
Ahh, yes that fixes things. Thanks!
I'd read that doc before getting started with Preact, but clearly I hadn't remembered everything :)
No problem, like the other person said before it could probably be higher up on that page ;)
Most helpful comment
Hi there! This is covered in What's Different but I'll summarize since it's come up before :)
Basically, preact's
render()does not replace by default. This is because doing so would require guessing which element you intended to replace (since you only pass the parent). Instead, there is a third argument you can pass, which is the element to replace. In your case, you just need to keep a reference to the root element, which is returned fromrender(), and pass it back on the next call:Also - just based on the querySelector all, you might be interested in knowing that preact is happy to render your app into
<body>. Unlike React, there is no need to wrap everything in a div :)Let me know if I didn't answer your question, or if we're all good and can close the issue out!