Skip to content

Commit

Permalink
Merge pull request #4563 from preactjs/handle-errors-during-hydration
Browse files Browse the repository at this point in the history
  • Loading branch information
JoviDeCroock authored Nov 23, 2024
2 parents 6590e26 + 38080ea commit 22621b6
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 9 deletions.
22 changes: 14 additions & 8 deletions src/diff/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,16 +274,22 @@ export function diff(
newVNode._original = null;
// if hydrating or creating initial tree, bailout preserves DOM:
if (isHydrating || excessDomChildren != null) {
newVNode._flags |= isHydrating
? MODE_HYDRATE | MODE_SUSPENDED
: MODE_SUSPENDED;
if (e.then) {
newVNode._flags |= isHydrating
? MODE_HYDRATE | MODE_SUSPENDED
: MODE_SUSPENDED;

while (oldDom && oldDom.nodeType === 8 && oldDom.nextSibling) {
oldDom = oldDom.nextSibling;
}
while (oldDom && oldDom.nodeType === 8 && oldDom.nextSibling) {
oldDom = oldDom.nextSibling;
}

excessDomChildren[excessDomChildren.indexOf(oldDom)] = null;
newVNode._dom = oldDom;
excessDomChildren[excessDomChildren.indexOf(oldDom)] = null;
newVNode._dom = oldDom;
} else {
for (let i = excessDomChildren.length; i--; ) {
removeNode(excessDomChildren[i]);
}
}
} else {
newVNode._dom = oldVNode._dom;
newVNode._children = oldVNode._children;
Expand Down
36 changes: 35 additions & 1 deletion test/browser/hydrate.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createElement, hydrate, Fragment } from 'preact';
import { createElement, hydrate, Fragment, Component } from 'preact';
import { setupRerender } from 'preact/test-utils';
import {
setupScratch,
teardown,
Expand Down Expand Up @@ -28,6 +29,7 @@ describe('hydrate()', () => {
let resetRemove;
let resetSetAttribute;
let resetRemoveAttribute;
let rerender;

before(() => {
resetAppendChild = logCall(Element.prototype, 'appendChild');
Expand All @@ -48,6 +50,7 @@ describe('hydrate()', () => {
});

beforeEach(() => {
rerender = setupRerender();
scratch = setupScratch();
attributesSpy = spyOnElementAttributes();
clearLog();
Expand Down Expand Up @@ -481,4 +484,35 @@ describe('hydrate()', () => {
expect(scratch.innerHTML).to.equal('<p>hello foo</p>');
expect(getLog()).to.deep.equal(['Comment.remove()', 'Comment.remove()']);
});

it('should work with error boundaries', () => {
scratch.innerHTML = '<div>Hello, World!</div>';
class Root extends Component {
constructor() {
super();
this.state = {};
}

componentDidCatch(error) {
this.setState({ error });
}

render() {
if (!this.state.error) {
return <App />;
} else {
return <div>Error!</div>;
}
}
}

function App() {
throw Error();
return createElement('div', {}, 'Hello, World!');
}

hydrate(<Root />, scratch);
rerender();
expect(scratch.innerHTML).to.equal('<div>Error!</div>');
});
});

0 comments on commit 22621b6

Please sign in to comment.