Render appends instead of replaces when there's an unexpected error
See original GitHub issueWhen your <Page/>
component unexpectedly throws, you may want to render an <ErrorPage/>
component. Right now render
will append the <ErrorPage/>
, rather than replace the <Page/>
.
Minimal Example:
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="duo"></div>
<script type="module">
import { h, render } from 'https://unpkg.com/preact@10.0.0/dist/preact.module.js'
function Page() {
return h('div', {}, ['A'])
}
function PageWithError() {
return h('div', {}, ['A', h(C, {})])
}
function ErrorPage({ error }) {
return h('div', {}, error.message)
}
const parent = document.getElementById("duo")
render(h(Page, {}), parent)
try {
render(h(PageWithError, {}), parent)
} catch(error) {
render(h(ErrorPage, { error }), parent)
}
</script>
</body>
</html>
Output:
A
C is not defined
Expected Output:
render(component, containerNode, [replaceNode])
behaves the same way regardless of if a component threw or not.
C is not defined
Here’s an interactive fiddle: https://jsfiddle.net/fwd4ktsy/6/
replaceNode
doesn’t seem to work
I’ve also tried a bunch of variations using the replaceNode
argument in render(component, containerNode, [replaceNode])
, unfortunately, while it fixes this problem I’m reporting here, I run into another problem where render removes the DOM nodes on the next render: https://jsfiddle.net/fwd4ktsy/7/
Hacky Solution
In the try-catch you can set parent.innerHTML = ''
which fixes the problem.
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="duo"></div>
<script type="module">
import { h, render } from 'https://unpkg.com/preact@10.0.0/dist/preact.module.js'
function Page() {
return h('div', {}, ['A'])
}
function PageWithError() {
return h('div', {}, ['A', h(C, {})])
}
function ErrorPage({ error }) {
return h('div', {}, error.message)
}
const parent = document.getElementById("duo")
render(h(Page, {}), parent)
try {
render(h(PageWithError, {}), parent)
} catch(error) {
parent.innerHTML = ''
render(h(ErrorPage, { error }), parent)
}
setTimeout(function() {
console.log('re-rendering')
render(h(Page, {}), parent)
}, 1000)
</script>
</body>
</html>
Let me know if you need any more info!
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (3 by maintainers)
Top GitHub Comments
This is a top-level example, you have to handle the way you see fit. In a previous project we made a button available to ensure that the user would not be on the fialing route and this would forward to the error logging service
@JoviDeCroock gotcha. I think that code would result in an infinite loop, since
children
is what would be throwing.