Skip to content

Commit e2eadeb

Browse files
committed
add react-router-dom
1 parent 6664b6d commit e2eadeb

File tree

13 files changed

+292
-47
lines changed

13 files changed

+292
-47
lines changed

package-lock.json

+40-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"dependencies": {
1313
"antd": "^5.13.1",
1414
"react": "^18.2.0",
15-
"react-dom": "^18.2.0"
15+
"react-dom": "^18.2.0",
16+
"react-router-dom": "^6.21.2"
1617
},
1718
"devDependencies": {
1819
"@types/react": "^18.2.43",

src/App.css

-42
This file was deleted.

src/components/layout/Layout.tsx

Whitespace-only changes.

src/components/layout/components/Sidebar.tsx

Whitespace-only changes.

src/main.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from "react";
22
import ReactDOM from "react-dom/client";
33
import App from "./App.tsx";
4-
import "./index.scss";
4+
import "./theme/global.scss";
55

66
ReactDOM.createRoot(document.getElementById("root")!).render(
77
<React.StrictMode>

src/pages/dashboard/Dashboard.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function Dashboard() {
2+
return <div>Dashboard</div>;
3+
}
4+
5+
export default Dashboard;
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const dashboardRoutes = [];

src/router/RouterProvider.tsx

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { RouterProvider as ReactRouterProvider } from "react-router-dom";
2+
3+
export const RouterProvider = () => {
4+
return (
5+
<ReactRouterProvider
6+
router={router}
7+
future={{
8+
// Wrap all state updates in React.startTransition()
9+
v7_startTransition: true,
10+
}}
11+
/>
12+
);
13+
};

src/router/routes.tsx

+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
import { createBrowserRouter } from "react-router-dom";
2+
3+
const routes = createBrowserRouter([
4+
{
5+
path: "/",
6+
/* Component() {
7+
let navigation = useNavigation();
8+
9+
return (
10+
<>
11+
{navigation.state !== "idle" ? (
12+
<div className="is-loading">Loading...</div>
13+
) : null}
14+
<Nav />
15+
<div className="content">
16+
<Outlet />
17+
</div>
18+
</>
19+
);
20+
}, */
21+
/* children: [
22+
{
23+
index: true,
24+
Component() {
25+
React.useEffect(() => {
26+
document.title = "Home";
27+
}, []);
28+
return <h1>Home</h1>;
29+
},
30+
},
31+
{
32+
path: "loader",
33+
async loader() {
34+
await new Promise((r) => setTimeout(r, 1000));
35+
return json({ message: "LOADER DATA" });
36+
},
37+
Component() {
38+
let data = useLoaderData() as { message: string };
39+
React.useEffect(() => {
40+
document.title = "Loader";
41+
}, []);
42+
return (
43+
<>
44+
<h1>Loader Page</h1>
45+
<p>Loader Data: {data.message}</p>
46+
</>
47+
);
48+
},
49+
},
50+
{
51+
path: "action",
52+
async action() {
53+
await new Promise((r) => setTimeout(r, 1000));
54+
return json({ message: "ACTION DATA" });
55+
},
56+
Component() {
57+
let data = useActionData() as { message: string } | undefined;
58+
React.useEffect(() => {
59+
document.title = "Action";
60+
}, []);
61+
return (
62+
<>
63+
<h1>Action Page</h1>
64+
<p>Action Data: {data?.message}</p>
65+
</>
66+
);
67+
},
68+
},
69+
{
70+
path: "defer",
71+
async loader({ request }) {
72+
return defer({
73+
critical: "CRITICAL PATH DATA",
74+
lazy: new Promise((r) => setTimeout(() => r("LAZY DATA"), 1000)),
75+
});
76+
},
77+
Component() {
78+
let data = useLoaderData() as {
79+
critical: string;
80+
lazy: Promise<string>;
81+
};
82+
React.useEffect(() => {
83+
document.title = "Defer";
84+
}, []);
85+
return (
86+
<>
87+
<h1>Defer</h1>
88+
<p>Critical Data: {data.critical}</p>
89+
<React.Suspense
90+
fallback={<p>Suspense boundary in the route...</p>}
91+
key={useLocation().key}
92+
>
93+
<Await resolve={data.lazy}>
94+
{(value) => <p>Lazy Data: {value}</p>}
95+
</Await>
96+
</React.Suspense>
97+
</>
98+
);
99+
},
100+
},
101+
{
102+
path: "defer-no-boundary",
103+
async loader({ request }) {
104+
let value = new URL(request.url).searchParams.get("value") || "";
105+
return defer({
106+
value,
107+
critical: "CRITICAL PATH DATA - NO BOUNDARY " + value,
108+
lazy: new Promise((r) =>
109+
setTimeout(() => r("LAZY DATA - NO BOUNDARY " + value), 1000)
110+
),
111+
});
112+
},
113+
Component() {
114+
let data = useLoaderData() as {
115+
value: string;
116+
data: string;
117+
critical: string;
118+
lazy: Promise<string>;
119+
};
120+
React.useEffect(() => {
121+
document.title = "Defer (No Boundary)";
122+
}, []);
123+
return (
124+
<>
125+
<h1>Defer No Boundary {data.value}</h1>
126+
<p>Critical Data: {data.critical}</p>
127+
<div>
128+
<Await resolve={data.lazy}>
129+
{(value) => <p>Lazy Data: {value}</p>}
130+
</Await>
131+
</div>
132+
</>
133+
);
134+
},
135+
},
136+
{
137+
path: "images",
138+
Component() {
139+
React.useEffect(() => {
140+
document.title = "Images";
141+
}, []);
142+
return (
143+
<div className="image-list">
144+
<h1>Image List</h1>
145+
<div>
146+
{images.map((src, idx) => (
147+
// Adds 'transitioning' class to the <a> during the transition
148+
<NavLink
149+
key={src}
150+
to={`/images/${idx}`}
151+
unstable_viewTransition
152+
>
153+
<p>Image Number {idx}</p>
154+
<img src={src} alt={`Img ${idx}`} />
155+
</NavLink>
156+
157+
// Render prop approach similar to isActive/isPending
158+
// <NavLink
159+
// key={src}
160+
// to={`/images/${idx}`}
161+
// unstable_viewTransition
162+
// >
163+
// {({ isTransitioning }) => (
164+
// <div className={isTransitioning ? "transitioning" : ""}>
165+
// <p>Image Number {idx}</p>
166+
// <img src={src} alt={`Img ${idx}`} />
167+
// </div>
168+
// )}
169+
// </NavLink>
170+
171+
// Manual hook based approach
172+
// <NavImage key={src} src={src} idx={idx} />
173+
))}
174+
</div>
175+
</div>
176+
);
177+
},
178+
},
179+
{
180+
path: "images/:id",
181+
Component() {
182+
let params = useParams();
183+
React.useEffect(() => {
184+
document.title = "Image " + params.id;
185+
}, [params.id]);
186+
return (
187+
<div className={`image-detail`}>
188+
<h1>Image Number {params.id}</h1>
189+
<img src={images[Number(params.id)]} alt={`${params.id}`} />
190+
</div>
191+
);
192+
},
193+
},
194+
], */
195+
},
196+
]);
197+
198+
export default routes;
File renamed without changes.

src/types/router.types.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type {
2+
ActionFunction,
3+
LazyRouteFunction,
4+
LoaderFunction,
5+
RouteObject,
6+
ShouldRevalidateFunction,
7+
} from "react-router-dom";
8+
9+
export interface IRoute {
10+
path?: string;
11+
index?: boolean;
12+
children?: React.ReactNode;
13+
caseSensitive?: boolean;
14+
id?: string;
15+
loader?: LoaderFunction;
16+
action?: ActionFunction;
17+
element?: React.ReactNode | null;
18+
hydrateFallbackElement?: React.ReactNode | null;
19+
errorElement?: React.ReactNode | null;
20+
Component?: React.ComponentType | null;
21+
HydrateFallback?: React.ComponentType | null;
22+
ErrorBoundary?: React.ComponentType | null;
23+
handle?: RouteObject["handle"];
24+
shouldRevalidate?: ShouldRevalidateFunction;
25+
lazy?: LazyRouteFunction<RouteObject>;
26+
}

task.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
- add router provider with dynamic routes
12

2-
3-
3+
- add protected page (guard)
4+
- add login page
5+
- add state management
6+
- add multi language support
7+
- add error boundary

0 commit comments

Comments
 (0)