Complete to "Client Side Routing"
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
import { Route as rootRoute } from './routes/__root'
|
import { Route as rootRoute } from './routes/__root'
|
||||||
import { Route as IndexImport } from './routes/index'
|
import { Route as IndexImport } from './routes/index'
|
||||||
|
import { Route as ContactsContractIdImport } from './routes/contacts.$contractId'
|
||||||
|
|
||||||
// Create/Update Routes
|
// Create/Update Routes
|
||||||
|
|
||||||
@@ -21,6 +22,12 @@ const IndexRoute = IndexImport.update({
|
|||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const ContactsContractIdRoute = ContactsContractIdImport.update({
|
||||||
|
id: '/contacts/$contractId',
|
||||||
|
path: '/contacts/$contractId',
|
||||||
|
getParentRoute: () => rootRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
// Populate the FileRoutesByPath interface
|
// Populate the FileRoutesByPath interface
|
||||||
|
|
||||||
declare module '@tanstack/react-router' {
|
declare module '@tanstack/react-router' {
|
||||||
@@ -32,6 +39,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof IndexImport
|
preLoaderRoute: typeof IndexImport
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute
|
||||||
}
|
}
|
||||||
|
'/contacts/$contractId': {
|
||||||
|
id: '/contacts/$contractId'
|
||||||
|
path: '/contacts/$contractId'
|
||||||
|
fullPath: '/contacts/$contractId'
|
||||||
|
preLoaderRoute: typeof ContactsContractIdImport
|
||||||
|
parentRoute: typeof rootRoute
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,32 +53,37 @@ declare module '@tanstack/react-router' {
|
|||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
|
'/contacts/$contractId': typeof ContactsContractIdRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
|
'/contacts/$contractId': typeof ContactsContractIdRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
__root__: typeof rootRoute
|
__root__: typeof rootRoute
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
|
'/contacts/$contractId': typeof ContactsContractIdRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileRouteTypes {
|
export interface FileRouteTypes {
|
||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
fileRoutesByFullPath: FileRoutesByFullPath
|
||||||
fullPaths: '/'
|
fullPaths: '/' | '/contacts/$contractId'
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to: '/'
|
to: '/' | '/contacts/$contractId'
|
||||||
id: '__root__' | '/'
|
id: '__root__' | '/' | '/contacts/$contractId'
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
IndexRoute: typeof IndexRoute
|
IndexRoute: typeof IndexRoute
|
||||||
|
ContactsContractIdRoute: typeof ContactsContractIdRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootRouteChildren: RootRouteChildren = {
|
const rootRouteChildren: RootRouteChildren = {
|
||||||
IndexRoute: IndexRoute,
|
IndexRoute: IndexRoute,
|
||||||
|
ContactsContractIdRoute: ContactsContractIdRoute,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const routeTree = rootRoute
|
export const routeTree = rootRoute
|
||||||
@@ -77,11 +96,15 @@ export const routeTree = rootRoute
|
|||||||
"__root__": {
|
"__root__": {
|
||||||
"filePath": "__root.tsx",
|
"filePath": "__root.tsx",
|
||||||
"children": [
|
"children": [
|
||||||
"/"
|
"/",
|
||||||
|
"/contacts/$contractId"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"/": {
|
"/": {
|
||||||
"filePath": "index.tsx"
|
"filePath": "index.tsx"
|
||||||
|
},
|
||||||
|
"/contacts/$contractId": {
|
||||||
|
"filePath": "contacts.$contractId.tsx"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createRootRoute } from '@tanstack/react-router';
|
import { Outlet, createRootRoute, Link } from '@tanstack/react-router';
|
||||||
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools';
|
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools';
|
||||||
|
|
||||||
export const Route = createRootRoute({
|
export const Route = createRootRoute({
|
||||||
@@ -24,14 +24,17 @@ export const Route = createRootRoute({
|
|||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href={`/contacts/1`}>Your Name</a>
|
<Link to="/contacts/$contractId" params={{ contractId: '1' }}>Your Name</Link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href={`/contacts/2`}>Your Friend</a>
|
<Link to="/contacts/$contractId" params={{ contractId: '2' }}>Your Friend</Link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
<div id={'detail'}>
|
||||||
|
<Outlet/>
|
||||||
|
</div>
|
||||||
<TanStackRouterDevtools/>
|
<TanStackRouterDevtools/>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
|||||||
101
src/routes/contacts.$contractId.tsx
Normal file
101
src/routes/contacts.$contractId.tsx
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import type { ContactRecord } from "@/data.ts";
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/contacts/$contractId')({
|
||||||
|
component: Contact,
|
||||||
|
});
|
||||||
|
|
||||||
|
function Contact() {
|
||||||
|
const contact = {
|
||||||
|
first: "Your",
|
||||||
|
last: "Name",
|
||||||
|
avatar: "https://placecats.com/200/200",
|
||||||
|
twitter: "your_handle",
|
||||||
|
notes: "Some notes",
|
||||||
|
favorite: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="contact">
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
alt={`${contact.first} ${contact.last} avatar`}
|
||||||
|
key={contact.avatar}
|
||||||
|
src={contact.avatar}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
{contact.first || contact.last ? (
|
||||||
|
<>
|
||||||
|
{contact.first} {contact.last}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<i>No Name</i>
|
||||||
|
)}
|
||||||
|
<Favorite contact={contact}/>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{contact.twitter ? (
|
||||||
|
<p>
|
||||||
|
<a
|
||||||
|
href={`https://twitter.com/${contact.twitter}`}
|
||||||
|
>
|
||||||
|
{contact.twitter}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{contact.notes ? <p>{contact.notes}</p> : null}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<form action="edit">
|
||||||
|
<button type="submit">Edit</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form
|
||||||
|
action="destroy"
|
||||||
|
method="post"
|
||||||
|
onSubmit={(event) => {
|
||||||
|
const response = confirm(
|
||||||
|
"Please confirm you want to delete this record."
|
||||||
|
);
|
||||||
|
if (!response) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button type="submit">Delete</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Favorite(
|
||||||
|
{
|
||||||
|
contact,
|
||||||
|
}: {
|
||||||
|
contact: Pick<ContactRecord, "favorite">;
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
const favorite = contact.favorite;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form method="post">
|
||||||
|
<button
|
||||||
|
aria-label={
|
||||||
|
favorite
|
||||||
|
? "Remove from favorites"
|
||||||
|
: "Add to favorites"
|
||||||
|
}
|
||||||
|
name="favorite"
|
||||||
|
value={favorite ? "false" : "true"}
|
||||||
|
>
|
||||||
|
{favorite ? "★" : "☆"}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user