Skip to content

Commit 9385124

Browse files
committed
Merge pull request #59 from g4rcez/loader-improvements
feat: loader improvements
2 parents ab85a06 + 2c6addb commit 9385124

File tree

20 files changed

+3001
-2428
lines changed

20 files changed

+3001
-2428
lines changed

docs/pnpm-lock.yaml

Lines changed: 1008 additions & 841 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/src/components/anchor.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Link, LinkProps } from "../exports";
2-
import React from "react";
32

43
export const Anchor = <TPath extends string>(props: LinkProps<TPath>) => (
54
<Link

docs/src/pages/install.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { DocumentPage } from "../components/document-page";
1+
import { useEffect } from "react";
22
import { Code } from "../components/code";
3+
import { DocumentPage } from "../components/document-page";
34
import { SubTitle } from "../components/subtitle";
45

56
const PackageManagers = [
Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,45 @@
1-
import { jsonResponse, useDataLoader } from "../../exports";
1+
import React from "react";
2+
import { useLoadingState, useQueryStringState } from "../../../../src/brouther/brouther";
3+
import { Form, jsonResponse, LoaderProps, useDataLoader } from "../../exports";
24

3-
export const loader = async () => {
4-
const response = await fetch("https://api.postmon.com.br/v1/cep/30260-070");
5-
console.log(await response.json());
6-
return jsonResponse({});
5+
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
6+
7+
export const loader = async (args: LoaderProps) => {
8+
const cep = (args.queryString as any).cep || "30260-070";
9+
const now = performance.now();
10+
await sleep(4000);
11+
console.log("LOADER JSON ->", cep, performance.now() - now);
12+
return jsonResponse({ cep });
713
};
814

9-
export const actions = async () => ({
10-
post: async () => {
11-
const response = await fetch("https://api.postmon.com.br/v1/cep/30260-070");
12-
console.log(await response.json());
13-
return jsonResponse({});
14-
},
15-
});
15+
const debounce = (fn: Function, ms: number = 0) => {
16+
let timeoutId: NodeJS.Timeout;
17+
return function (...args: any[]) {
18+
clearTimeout(timeoutId);
19+
timeoutId = setTimeout(() => fn.apply(this, args), ms);
20+
};
21+
};
1622

1723
export default function LoaderPage() {
1824
const data = useDataLoader<typeof loader>();
19-
return <div>{JSON.stringify(data, null, 4)}</div>;
25+
const [q, setQ] = useQueryStringState<any>();
26+
const loading = useLoadingState()
27+
return (
28+
<div className="h-full flex flex-col gap-6 items-center justify-center w-full">
29+
<p>{loading ? "Loading..." : ""}</p>
30+
<Form method="get" encType="json" className="flex gap-4">
31+
<input name="cep" className="bg-white border p-1" />
32+
<button type="submit">Test</button>
33+
</Form>
34+
<input
35+
className="bg-white border p-1"
36+
placeholder="Debounce test"
37+
onChange={debounce((e: React.ChangeEvent<HTMLInputElement>) => {
38+
setQ((prev: any) => ({ ...prev, query: e.target.value }));
39+
console.log("After 2 seconds");
40+
}, 1200)}
41+
/>
42+
<div>{JSON.stringify({ data, q }, null, 4)}</div>
43+
</div>
44+
);
2045
}

docs/src/pages/playground/main-playground.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Code } from "../../components/code";
66
import { DocumentPage } from "../../components/document-page";
77
import { InlineCode } from "../../components/inline-code";
88
import { SubTitle } from "../../components/subtitle";
9-
import { Actions, Form, redirectResponse, usePaths } from "../../exports";
9+
import { Actions, Form, jsonResponse, redirectResponse, useNavigation, usePaths } from "../../exports";
1010
import { router } from "../../router";
1111

1212
declare global {
@@ -15,13 +15,18 @@ declare global {
1515
}
1616
}
1717

18+
export const loader = async () => {
19+
await new Promise((resolve) => setTimeout(resolve, 4000));
20+
return jsonResponse({});
21+
};
22+
1823
export const actions: Actions<"/playground?type=status"> = async () => ({
1924
post: async (args) => {
2025
console.log(args);
2126
const body = await args.request.json();
22-
const url = args.link("/playground?type=status", { type: body.type }, { type: body.type });
27+
const url = args.link(args.path, { type: body.type }, { type: body.type });
2328
console.log(url, body);
24-
return redirectResponse(args.link);
29+
return redirectResponse(url);
2530
},
2631
});
2732

@@ -31,7 +36,7 @@ const parseParams = (txt: string): Match[] => {
3136
const regex = /(\/:\w+|\/<\w+:\w+>)/gm;
3237
const result = txt.match(regex);
3338
if (!result) return [];
34-
return [...new Set(result)].map((x) => {
39+
return result.map((x) => {
3540
if (x.includes("<")) {
3641
const [name, value] = x
3742
.replace(/([<>])/g, "")
@@ -78,6 +83,7 @@ const PathParser = () => {
7883
};
7984

8085
export default function MainPlayground() {
86+
const navigation = useNavigation();
8187
useEffect(() => {
8288
window.brouther = router;
8389
}, []);
@@ -110,12 +116,18 @@ export default function MainPlayground() {
110116
Go to {"<Brouther />"} ({router.links.brouther})
111117
</Anchor>
112118
</nav>
119+
<button
120+
onClick={() => {
121+
navigation.back();
122+
}}
123+
>
124+
Back in history
125+
</button>
113126
<PathParser />
114127
<Form method="post" encType="json">
115128
<input name="type" placeholder="Type to QueryString" />
116129
<button type="submit">Submit</button>
117130
</Form>
118-
119131
<pre>
120132
<code>{JSON.stringify(usePaths(), null, 4)}</code>
121133
</pre>

docs/src/router.tsx

Lines changed: 62 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,64 +3,66 @@ import { asyncActions, asyncComponent, asyncLoader, createRouter } from "./expor
33
import { ErrorElementExample } from "./pages/routers/error-element";
44

55
export const router = createRouter(
6-
{
7-
actions: { path: "/form/actions", element: asyncComponent(() => import("./pages/form/actions")) },
8-
decisions: { path: "/decision-records", element: asyncComponent(() => import("./pages/decision-records")) },
9-
aliases: { path: "/route-alias", element: <Fragment /> },
10-
basicSetup: { path: "/basic-setup", element: asyncComponent(() => import("./pages/basic-setup")) },
11-
brouther: { path: "/components/brouther", element: asyncComponent(() => import("./pages/brouther")) },
12-
createMappedRouter: {
13-
path: "/routers/create-mapped-router",
14-
element: asyncComponent(() => import("./pages/routers/create-mapped-router")),
15-
},
16-
createRouter: {
17-
path: "/routers/create-router",
18-
element: asyncComponent(() => import("./pages/routers/create-router")),
19-
},
20-
playground: {
21-
path: "/playground?type=string",
22-
actions: asyncActions(() => import("./pages/playground/main-playground")),
23-
element: asyncComponent(() => import("./pages/playground/main-playground")),
24-
},
25-
form: {
26-
path: "/form",
27-
element: asyncComponent(() => import("./pages/form/form")),
28-
data: {
29-
number: 1,
30-
},
31-
},
32-
hooks: { path: "/hooks", element: <Fragment /> },
33-
index: { path: "/", element: asyncComponent(() => import("./pages/index")) },
34-
install: { path: "/install", element: asyncComponent(() => import("./pages/install")) },
35-
linkComponent: { path: "/components/link", element: asyncComponent(() => import("./pages/link")) },
36-
loaders: { path: "/form/loaders", element: asyncComponent(() => import("./pages/form/loaders")) },
37-
paths: { path: "/paths", element: <Fragment /> },
38-
queryString: { path: "/query-string", element: <Fragment /> },
39-
tricksAndTips: { path: "/form/tricks-and-tips", element: asyncComponent(() => import("./pages/form/tricks")) },
40-
usePage: { path: "/hooks/use-page", element: asyncComponent(() => import("./pages/hooks/use-page")) },
41-
usePaths: { path: "/hooks/use-paths", element: asyncComponent(() => import("./pages/hooks/use-paths")) },
42-
useNavigation: {
43-
path: "/hooks/use-navigation",
44-
element: asyncComponent(() => import("./pages/hooks/use-navigation")),
45-
},
46-
errorElement: {
47-
path: "/routers/error-element",
48-
errorElement: <ErrorElementExample />,
49-
element: asyncComponent(() => import("./pages/routers/error-element")),
50-
},
51-
scroll: { path: "/components/scroll", element: asyncComponent(() => import("./pages/scroll")) },
52-
await: { path: "/components/await", element: asyncComponent(() => import("./pages/await")) },
53-
outlet: { path: "/components/outlet", element: asyncComponent(() => import("./pages/outlet")) },
54-
test: {
55-
path: "/test/:uuid?type=string",
56-
element: asyncComponent(() => import("./pages/playground/main-playground")),
57-
},
58-
loaderTest: {
59-
path: "/playground/loader",
60-
element: asyncComponent(() => import("./pages/playground/loader")),
61-
loader: asyncLoader(() => import("./pages/playground/loader")),
62-
actions: asyncActions(() => import("./pages/playground/loader")),
63-
},
64-
} as const,
65-
"/"
6+
{
7+
actions: { path: "/form/actions", element: asyncComponent(() => import("./pages/form/actions")) },
8+
decisions: { path: "/decision-records", element: asyncComponent(() => import("./pages/decision-records")) },
9+
aliases: { path: "/route-alias", element: <Fragment/> },
10+
basicSetup: { path: "/basic-setup", element: asyncComponent(() => import("./pages/basic-setup")) },
11+
brouther: { path: "/components/brouther", element: asyncComponent(() => import("./pages/brouther")) },
12+
createMappedRouter: {
13+
path: "/routers/create-mapped-router",
14+
element: asyncComponent(() => import("./pages/routers/create-mapped-router")),
15+
},
16+
createRouter: {
17+
path: "/routers/create-router",
18+
element: asyncComponent(() => import("./pages/routers/create-router")),
19+
},
20+
playground: {
21+
path: "/playground?type=string",
22+
actions: asyncActions(() => import("./pages/playground/main-playground")),
23+
loader: asyncLoader(() => import("./pages/playground/main-playground")),
24+
element: asyncComponent(() => import("./pages/playground/main-playground")),
25+
loadingElement: <div className="h-full w-full flex items-center justify-center">Loading...</div>,
26+
},
27+
form: {
28+
path: "/form",
29+
element: asyncComponent(() => import("./pages/form/form")),
30+
data: {
31+
number: 1,
32+
},
33+
},
34+
hooks: { path: "/hooks", element: <Fragment/> },
35+
index: { path: "/", element: asyncComponent(() => import("./pages/index")) },
36+
install: { path: "/install", element: asyncComponent(() => import("./pages/install")) },
37+
linkComponent: { path: "/components/link", element: asyncComponent(() => import("./pages/link")) },
38+
loaders: { path: "/form/loaders", element: asyncComponent(() => import("./pages/form/loaders")) },
39+
paths: { path: "/paths", element: <Fragment/> },
40+
queryString: { path: "/query-string", element: <Fragment/> },
41+
tricksAndTips: { path: "/form/tricks-and-tips", element: asyncComponent(() => import("./pages/form/tricks")) },
42+
usePage: { path: "/hooks/use-page", element: asyncComponent(() => import("./pages/hooks/use-page")) },
43+
usePaths: { path: "/hooks/use-paths", element: asyncComponent(() => import("./pages/hooks/use-paths")) },
44+
useNavigation: {
45+
path: "/hooks/use-navigation",
46+
element: asyncComponent(() => import("./pages/hooks/use-navigation")),
47+
},
48+
errorElement: {
49+
path: "/routers/error-element",
50+
errorElement: <ErrorElementExample/>,
51+
element: asyncComponent(() => import("./pages/routers/error-element")),
52+
},
53+
scroll: { path: "/components/scroll", element: asyncComponent(() => import("./pages/scroll")) },
54+
await: { path: "/components/await", element: asyncComponent(() => import("./pages/await")) },
55+
outlet: { path: "/components/outlet", element: asyncComponent(() => import("./pages/outlet")) },
56+
test: {
57+
path: "/test/:uuid?type=string",
58+
element: asyncComponent(() => import("./pages/playground/main-playground")),
59+
},
60+
loaderTest: {
61+
path: "/playground/loader",
62+
element: asyncComponent(() => import("./pages/playground/loader")),
63+
loader: asyncLoader(() => import("./pages/playground/loader")),
64+
actions: asyncActions(() => import("./pages/playground/loader")),
65+
},
66+
} as const,
67+
"/",
6668
);

0 commit comments

Comments
 (0)