Skip to content

Commit

Permalink
Merge pull request #11 from sventschui/suspense-issue
Browse files Browse the repository at this point in the history
Suspense should be no-op during prepass
  • Loading branch information
sventschui authored Jul 19, 2020
2 parents fecca96 + d7b2403 commit b51bc80
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 3 deletions.
8 changes: 7 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow
import { assign, getChildren } from "./util";
import { options, Fragment, Component } from "preact";
import { Suspense } from "preact/compat";

const createContextDefaultValue = "__p";
const createContextDefaultValueNew = "__";
Expand Down Expand Up @@ -35,7 +36,11 @@ export default function prepass(
children = [];
context = context || {};

if (typeof nodeName === "function" && nodeName !== Fragment) {
if (
typeof nodeName === "function" &&
nodeName !== Fragment &&
nodeName !== Suspense // We're handling Suspense the same way as we do fragments as we do not want something to catch promises during prepass
) {
let doRender /* : () => Promise<void> */;
let c = (vnode.__c = new Component(props, context));
c.__v = vnode;
Expand Down Expand Up @@ -82,6 +87,7 @@ export default function prepass(
};
} else {
isClassComponent = true;

// class-based components
// c = new nodeName(props, context);
c = vnode.__c = new nodeName(props, context);
Expand Down
50 changes: 49 additions & 1 deletion src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from "preact";
import prepass from ".";
import { useState, useEffect, useLayoutEffect } from "preact/hooks";
import { lazy } from "preact/compat";
import { lazy, Suspense } from "preact/compat";
import renderToString from "preact-render-to-string";

function Suspendable_({ getPromise, isDone }) {
Expand Down Expand Up @@ -514,6 +514,54 @@ describe("prepass", () => {
await prepass(tree);
expect(renderToString(tree)).toEqual("<div>I'm a bit lazy</div>");
});

it("should support lazy wrapped in Suspense with renderToString", async () => {
function LazyComponentImpl() {
return <div>I'm a bit lazy</div>;
}
const LazyComponent = lazy(() => Promise.resolve(LazyComponentImpl));
function App() {
return (
<Suspense fallback={null}>
<LazyComponent />
</Suspense>
);
}

const tree = <App />;
await prepass(tree);
expect(renderToString(tree)).toEqual("<div>I'm a bit lazy</div>");
});

it("should support lazy wrapped in ErrorBoundary with renderToString", async () => {
function LazyComponentImpl() {
return <div>I'm a bit lazy</div>;
}
const LazyComponent = lazy(() => Promise.resolve(LazyComponentImpl));
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidCatch(e) {
this.setState({ e });
}
render({ children }, { e }) {
return e ? "error" : children;
}
}
function App() {
return (
<ErrorBoundary>
<LazyComponent />
</ErrorBoundary>
);
}

const tree = <App />;
await prepass(tree);
expect(renderToString(tree)).toEqual("<div>I'm a bit lazy</div>");
});
});

describe("Suspense", () => {
Expand Down
2 changes: 2 additions & 0 deletions typings/index.d.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { createElement, VNode, Component } from "preact";
const vnode = createElement("div", {});
const asyncVisitor = (vnode: VNode, component: Component) => Promise.resolve();
const syncVisitor = (vnode: VNode, component: Component) => undefined;
const syncVoidVisitor = (vnode: VNode, component: Component) => {};
const emptyContext = {};
const filledContext = { foo: "bar" };

const promise01: Promise<any> = prepass(vnode);
const promise02: Promise<any> = prepass(vnode, asyncVisitor);
const promise03: Promise<any> = prepass(vnode, syncVisitor);
const promise08: Promise<any> = prepass(vnode, syncVoidVisitor);
const promise04: Promise<any> = prepass(vnode, syncVisitor, undefined);
const promise05: Promise<any> = prepass(vnode, syncVisitor, emptyContext);
const promise06: Promise<any> = prepass(vnode, syncVisitor, filledContext);
Expand Down
5 changes: 4 additions & 1 deletion typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { Component, VNode } from "preact";

declare function prepass(
vnode: VNode,
visitor?: (vnode: VNode, component: Component) => Promise<any> | undefined,
visitor?: (
vnode: VNode,
component: Component
) => Promise<any> | undefined | void,
context?: Object | undefined
): Promise<void | Array<void>>;

Expand Down

0 comments on commit b51bc80

Please sign in to comment.