Skip to content

Commit 86c3f98

Browse files
committed
Merge pull request #43 from g4rcez/await-component
await component
2 parents 2dc74a7 + 3a4caf1 commit 86c3f98

File tree

6 files changed

+74
-9
lines changed

6 files changed

+74
-9
lines changed

playground/src/main.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Brouther, Scroll } from "../../src";
55
import { router } from "./routes";
66
import "./index.css";
77

8-
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
8+
ReactDOM.createRoot(document.getElementById("root")!).render(
99
<React.StrictMode>
1010
<React.Suspense fallback={<div>Loading...</div>}>
1111
<Brouther ErrorElement={<p>Error</p>} config={router.config}>

playground/src/pages/root.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1-
import { ActionProps, createFormPath, Form, useScroll, jsonResponse, LoaderProps, redirectResponse, useDataLoader, useLoadingState } from "../../../src";
1+
import {
2+
ActionProps,
3+
Await,
4+
createFormPath,
5+
Form,
6+
jsonResponse,
7+
LoaderProps,
8+
redirectResponse,
9+
useDataLoader,
10+
useLoadingState,
11+
useScroll,
12+
} from "../../../src";
213
import { useEffect, useState } from "react";
314
import { Input } from "../components/input";
415

@@ -23,6 +34,8 @@ type State = { person: { name: string; surname: string; birthday: Date } };
2334

2435
const path = createFormPath<State>();
2536

37+
const createPromise = (ms: number) => new Promise((res) => setTimeout(res, ms));
38+
2639
export default function Root() {
2740
const data = useDataLoader<typeof loader>();
2841
const qs = data?.qs;
@@ -51,10 +64,11 @@ export default function Root() {
5164
<section className="flex flex-col gap-12">
5265
<h2 className="font-bold text-3xl">Form post action - json</h2>
5366
<h2 className="font-medium text-xl">
54-
<a href="#main">
55-
{show ? "SHOW" : "CLOSE"}
56-
</a>
67+
<a href="#main">{show ? "SHOW" : "CLOSE"}</a>
5768
</h2>
69+
<Await loadingElement={<p>Loading...</p>} promise={createPromise(2000)}>
70+
{() => <p>Cool</p>}
71+
</Await>
5872
<button
5973
className="duration-300 transition-colors ease-in-out bg-red-500 text-white font-semibold text-lg rounded-lg w-fit px-4 py-1 link:bg-red-600"
6074
onClick={() => setError(new Error("BOOM"))}
@@ -198,7 +212,9 @@ export default function Root() {
198212
subtilitatis, obscuris et malesuada fames.Paullum deliquit, ponderibus modulisque suis ratio utitur.Ullamco laboris nisi ut
199213
aliquid ex ea commodi consequat.Cras mattis iudicium purus sit amet fermentum. ut aliquid ex ea commodi consequat.Cras mattis
200214
iudicium purus sit amet fermentum.
201-
<span id="main" className="font-bold text-blue-800">iudicium purus sit amet fermentum.</span>
215+
<span id="main" className="font-bold text-blue-800">
216+
iudicium purus sit amet fermentum.
217+
</span>
202218
</p>
203219
) : null}
204220
<h2 className="text-3xl mt-96">

playground/src/pages/user.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { InferLoader, jsonResponse, LoaderProps, useDataLoader } from "../../../src";
1+
import { jsonResponse, LoaderProps, useDataLoader } from "../../../src";
22
import Data from "../data/users.json";
33

44
export const loader = async (args: LoaderProps<"/user/<id:string>?sort=string">) => {
@@ -7,7 +7,7 @@ export const loader = async (args: LoaderProps<"/user/<id:string>?sort=string">)
77
};
88

99
export default function UserPage() {
10-
const data = useDataLoader<InferLoader<typeof loader>>();
10+
const data = useDataLoader<typeof loader>();
1111
return (
1212
<div>
1313
<h1>Hero: {data?.hero?.name}</h1>

playground/src/routes.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type IndexRoute = Paths["index"];
99

1010
const ErrorElement = () => {
1111
const [error] = useRouteError();
12+
console.error(error)
1213
return (
1314
<p>
1415
Fail...Error Boom <Link href={"/blog"}>Go to Blog</Link>
@@ -29,4 +30,4 @@ export const router = createMappedRouter({
2930
loader: asyncLoader(() => import("./pages/user")),
3031
element: asyncComponent(() => import("./pages/user")),
3132
}),
32-
} as const);
33+
});

src/brouther/await.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React, { useEffect, useState } from "react";
2+
3+
type AwaitProps<T extends Promise<any>> = {
4+
promise: T;
5+
loadingElement?: React.ReactElement;
6+
errorElement?: (error: any) => React.ReactElement;
7+
children: (resolved: Awaited<T>) => React.ReactElement;
8+
};
9+
10+
type PromiseResolved<T extends Promise<any>> = { resolved: Awaited<T> | undefined; error: boolean };
11+
12+
const resolvePromise = async <T extends Promise<any>>(
13+
promise: T
14+
): Promise<
15+
| {
16+
resolved: Awaited<T>;
17+
error: false;
18+
}
19+
| {
20+
error: true;
21+
resolved: undefined;
22+
}
23+
> => {
24+
try {
25+
const resolved = await promise;
26+
return { resolved, error: false };
27+
} catch (e) {
28+
return { resolved: undefined, error: true };
29+
}
30+
};
31+
32+
const InnerAwait = <T extends Promise<any>>(props: AwaitProps<T>) => {
33+
const [data, setData] = useState<PromiseResolved<T> | undefined>(undefined);
34+
35+
useEffect(() => void resolvePromise(props.promise).then(setData), [props.promise]);
36+
37+
if (data === undefined) return props.loadingElement;
38+
if (!data.error) return props.children(data.resolved!);
39+
if (data.error && props.errorElement) return props.errorElement(data!.error);
40+
return props.loadingElement;
41+
};
42+
43+
export const Await = <T extends Promise<any>>(props: AwaitProps<T>) => (
44+
<React.Suspense fallback={props.loadingElement}>
45+
<InnerAwait errorElement={props.errorElement} promise={props.promise} loadingElement={props.loadingElement} children={props.children} />
46+
</React.Suspense>
47+
);

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,4 @@ export { urlSearchParamsToJson, jsonToURLSearchParams, formToJson } from "./form
4949
export { createFormPath } from "./form/form-path";
5050
export { redirectResponse, jsonResponse, type InferLoader, type CustomResponse } from "./brouther/brouther-response";
5151
export { waitFor, Scroll, useScroll } from "./brouther/scroll";
52+
export { Await } from "./brouther/await";

0 commit comments

Comments
 (0)