Skip to content

Commit 6fcdfbb

Browse files
committed
query key changes
1 parent c7729b1 commit 6fcdfbb

File tree

7 files changed

+141
-54
lines changed

7 files changed

+141
-54
lines changed

apps/2-vite-useeffect/src/AppLayout.tsx

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
import { Anchor, AppShell, Burger, Group } from "@mantine/core";
1+
import {
2+
Anchor,
3+
AppShell,
4+
Breadcrumbs,
5+
Burger,
6+
Group,
7+
Stack,
8+
} from "@mantine/core";
29
import { useDisclosure } from "@mantine/hooks";
310
import { IconHome, IconUsersGroup } from "@tabler/icons-react";
4-
import { Link } from "react-router-dom";
11+
import { useMemo } from "react";
12+
import { Link, useLocation } from "react-router-dom";
513

614
interface AppLayoutProps {
715
children: React.ReactNode;
@@ -23,6 +31,25 @@ const links = [
2331
];
2432

2533
export function AppLayout({ children }: AppLayoutProps) {
34+
const { pathname } = useLocation();
35+
36+
const breadCrumbLinks = useMemo(() => {
37+
const routes = pathname.split("/");
38+
routes.shift();
39+
const links: string[] = [];
40+
for (let i = 0; i < routes.length + 1; i++) {
41+
if (routes[i] && routes[i] !== "/")
42+
if (routes[i] === "posts") {
43+
links.push(`/`);
44+
} else links.push(`/${routes.slice(0, i + 1).join("/")}`);
45+
}
46+
return links;
47+
}, [pathname]);
48+
49+
if (breadCrumbLinks.length === 1) {
50+
breadCrumbLinks.unshift("/");
51+
}
52+
2653
const [opened, { toggle }] = useDisclosure();
2754

2855
return (
@@ -44,7 +71,28 @@ export function AppLayout({ children }: AppLayoutProps) {
4471
</Anchor>
4572
))}
4673
</AppShell.Navbar>
47-
<AppShell.Main>{children}</AppShell.Main>
74+
<AppShell.Main>
75+
<Stack gap="md" mt="lg">
76+
<Breadcrumbs aria-label="breadcrumb" pb="md">
77+
{breadCrumbLinks.map((link, index) => (
78+
<Anchor
79+
c="inherit"
80+
component={Link}
81+
key={index}
82+
td="none"
83+
to={link}
84+
tt="capitalize"
85+
style={{
86+
cursor: "pointer",
87+
}}
88+
>
89+
{link === "/" ? "Home Feed" : link.split("/").pop()}
90+
</Anchor>
91+
))}
92+
</Breadcrumbs>
93+
{children}
94+
</Stack>
95+
</AppShell.Main>
4896
</AppShell>
4997
);
5098
}

apps/3-vite-reactquery/src/AppLayout.tsx

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
import { Anchor, AppShell, Burger, Group } from "@mantine/core";
1+
import {
2+
Anchor,
3+
AppShell,
4+
Breadcrumbs,
5+
Burger,
6+
Group,
7+
Stack,
8+
} from "@mantine/core";
29
import { useDisclosure } from "@mantine/hooks";
310
import { IconHome, IconUsersGroup } from "@tabler/icons-react";
4-
import { Link } from "react-router-dom";
11+
import { useMemo } from "react";
12+
import { Link, useLocation } from "react-router-dom";
513

614
interface AppLayoutProps {
715
children: React.ReactNode;
@@ -23,6 +31,25 @@ const links = [
2331
];
2432

2533
export function AppLayout({ children }: AppLayoutProps) {
34+
const { pathname } = useLocation();
35+
36+
const breadCrumbLinks = useMemo(() => {
37+
const routes = pathname.split("/");
38+
routes.shift();
39+
const links: string[] = [];
40+
for (let i = 0; i < routes.length + 1; i++) {
41+
if (routes[i] && routes[i] !== "/")
42+
if (routes[i] === "posts") {
43+
links.push(`/`);
44+
} else links.push(`/${routes.slice(0, i + 1).join("/")}`);
45+
}
46+
return links;
47+
}, [pathname]);
48+
49+
if (breadCrumbLinks.length === 1) {
50+
breadCrumbLinks.unshift("/");
51+
}
52+
2653
const [opened, { toggle }] = useDisclosure();
2754

2855
return (
@@ -44,7 +71,28 @@ export function AppLayout({ children }: AppLayoutProps) {
4471
</Anchor>
4572
))}
4673
</AppShell.Navbar>
47-
<AppShell.Main>{children}</AppShell.Main>
74+
<AppShell.Main>
75+
<Stack gap="md" mt="lg">
76+
<Breadcrumbs aria-label="breadcrumb" pb="md">
77+
{breadCrumbLinks.map((link, index) => (
78+
<Anchor
79+
c="inherit"
80+
component={Link}
81+
key={index}
82+
td="none"
83+
to={link}
84+
tt="capitalize"
85+
style={{
86+
cursor: "pointer",
87+
}}
88+
>
89+
{link === "/" ? "Home Feed" : link.split("/").pop()}
90+
</Anchor>
91+
))}
92+
</Breadcrumbs>
93+
{children}
94+
</Stack>
95+
</AppShell.Main>
4896
</AppShell>
4997
);
5098
}

apps/3-vite-reactquery/src/pages/HomePage.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ import { type IPost } from "../api-types";
1515
import { useQuery } from "@tanstack/react-query";
1616

1717
export function HomePage() {
18-
//posts states
18+
//load posts
1919
const {
2020
data: posts,
2121
isError: isErrorLoadingPosts,
2222
isFetching: isFetchingPosts,
2323
isLoading: isLoadingPosts,
2424
} = useQuery({
25-
queryKey: ["posts"],
25+
queryKey: ["/posts"],
2626
queryFn: async () => {
2727
const fetchUrl = new URL(`http://localhost:3333/posts`);
2828

apps/3-vite-reactquery/src/pages/PostPage.tsx

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const PostPage = () => {
3030
isLoading: isLoadingPost,
3131
isError: isErrorLoadingPosts,
3232
} = useQuery({
33-
queryKey: ["post", +postId!],
33+
queryKey: [`/posts/${postId}`],
3434
queryFn: async () => {
3535
const response = await fetch(`http://localhost:3333/posts/${postId}`);
3636
return response.json() as Promise<IPost>;
@@ -44,7 +44,7 @@ export const PostPage = () => {
4444
isError: isErrorLoadingUser,
4545
} = useQuery({
4646
enabled: !!post?.userId,
47-
queryKey: ["user", +post?.userId!],
47+
queryKey: [`/users/${post?.userId}`],
4848
queryFn: async () => {
4949
const response = await fetch(
5050
`http://localhost:3333/users/${post?.userId}`
@@ -61,7 +61,7 @@ export const PostPage = () => {
6161
isError: isErrorLoadingComments,
6262
refetch: refetchComments,
6363
} = useQuery({
64-
queryKey: ["comments", +postId!],
64+
queryKey: [`/posts/${postId}/comments`],
6565
queryFn: async () => {
6666
const response = await fetch(
6767
`http://localhost:3333/posts/${postId}/comments`
@@ -100,13 +100,6 @@ export const PostPage = () => {
100100
},
101101
});
102102

103-
const handleDeleteComment = useCallback(
104-
(commentId: number) => {
105-
deleteComment(commentId);
106-
},
107-
[deleteComment]
108-
);
109-
110103
// Post new comment - with optimistic updates!
111104
const [commentText, setCommentText] = useState("");
112105

@@ -256,7 +249,7 @@ export const PostPage = () => {
256249
right={10}
257250
top={10}
258251
variant="subtle"
259-
onClick={() => handleDeleteComment(comment.id)}
252+
onClick={() => deleteComment(comment.id)}
260253
>
261254
<IconTrash />
262255
</ActionIcon>

apps/3-vite-reactquery/src/pages/UserPage.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const UserPage = () => {
2525
isError: isErrorLoadingUser,
2626
} = useQuery({
2727
enabled: !!userId,
28-
queryKey: ["user", +userId!],
28+
queryKey: [`/users/${userId}`],
2929
queryFn: async () => {
3030
const response = await fetch(`http://localhost:3333/users/${userId}`);
3131
return response.json() as Promise<IUser>;
@@ -39,12 +39,9 @@ export const UserPage = () => {
3939
isFetching: isFetchingPosts,
4040
isError: isErrorLoadingPosts,
4141
} = useQuery({
42-
queryKey: ["posts", +userId!],
42+
queryKey: [`/posts?userId=${userId}`],
4343
queryFn: async () => {
44-
const fetchUrl = new URL(`http://localhost:3333/posts`);
45-
if (userId) {
46-
fetchUrl.searchParams.set("userId", userId);
47-
}
44+
const fetchUrl = new URL(`http://localhost:3333/posts?userId=${userId}`);
4845
const response = await fetch(fetchUrl.href);
4946
return response.json() as Promise<IPost[]>;
5047
},

apps/3-vite-reactquery/src/pages/UsersPage.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const UsersPage = () => {
1616
isFetching: isFetchingUser,
1717
isLoading: isLoadingUser,
1818
} = useQuery({
19-
queryKey: ["users"],
19+
queryKey: [`/users`],
2020
queryFn: async () => {
2121
const response = await fetch(`http://localhost:3333/users`);
2222
return response.json() as Promise<IUser[]>;
@@ -73,8 +73,9 @@ export const UsersPage = () => {
7373
}
7474
mantineTableBodyRowProps={({ row }) => ({
7575
onMouseEnter: () => {
76+
//same fetch as in UserPage.tsx
7677
queryClient.prefetchQuery({
77-
queryKey: ["user", +row.original.id],
78+
queryKey: [`/users/${row.original.id}`],
7879
queryFn: async () => {
7980
const response = await fetch(
8081
`http://localhost:3333/users/${row.original.id}`

apps/5-nextjs-ssr/src/pages/posts/[id].tsx

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -70,53 +70,53 @@ export default function PostPage({
7070
const queryClient = useQueryClient();
7171
const { id: postId } = useParams();
7272

73-
//load post - with initial data from SSR
73+
//load post - with initial data from server
7474
const {
7575
data: post,
7676
isLoading: isLoadingPost,
7777
isError: isErrorLoadingPosts,
7878
} = useQuery({
79-
queryKey: ["post", postId],
79+
initialData: initialPost,
80+
queryKey: [`/posts/${postId}`],
8081
queryFn: async () => {
8182
const response = await fetch(`http://localhost:3333/posts/${postId}`);
8283
return response.json() as Promise<IPost>;
8384
},
84-
initialData: initialPost, //SSR, with refresh
8585
});
8686

87-
//load comments - with initial data from SSR
87+
//load user - depends on user id from post
8888
const {
89-
data: comments,
90-
isLoading: isLoadingComments,
91-
isFetching: isFetchingComments,
92-
isError: isErrorLoadingComments,
93-
refetch: refetchComments,
89+
data: user,
90+
isLoading: isLoadingUser,
91+
isError: isErrorLoadingUser,
9492
} = useQuery({
95-
queryKey: ["comments", postId],
93+
enabled: !!post?.userId,
94+
queryKey: [`/users/${post?.userId}`],
9695
queryFn: async () => {
9796
const response = await fetch(
98-
`http://localhost:3333/posts/${postId}/comments`,
97+
`http://localhost:3333/users/${post?.userId}`
9998
);
100-
return response.json() as Promise<IComment[]>;
99+
return response.json() as Promise<IUser>;
101100
},
102-
initialData: initialComments, //SSR, with refresh
103-
refetchInterval: 10000, // 10 seconds
104101
});
105102

106-
//load user - depends on user id from post so client-side only
103+
//load comments - with initial data from server
107104
const {
108-
data: user,
109-
isLoading: isLoadingUser,
110-
isError: isErrorLoadingUser,
105+
data: comments,
106+
isLoading: isLoadingComments,
107+
isFetching: isFetchingComments,
108+
isError: isErrorLoadingComments,
109+
refetch: refetchComments,
111110
} = useQuery({
112-
enabled: !!post?.userId,
113-
queryKey: ["user", post?.userId],
111+
initialData: initialComments,
112+
queryKey: [`/posts/${postId}/comments`],
114113
queryFn: async () => {
115114
const response = await fetch(
116-
`http://localhost:3333/users/${post?.userId}`,
115+
`http://localhost:3333/posts/${postId}/comments`
117116
);
118-
return response.json() as Promise<IUser>;
117+
return response.json() as Promise<IComment[]>;
119118
},
119+
refetchInterval: 10000, // 10 seconds
120120
});
121121

122122
//delete comment, refresh comments after delete
@@ -130,7 +130,7 @@ export default function PostPage({
130130
`http://localhost:3333/comments/${commentId}`,
131131
{
132132
method: "DELETE",
133-
},
133+
}
134134
);
135135
return response.json() as Promise<IComment>;
136136
},
@@ -139,7 +139,7 @@ export default function PostPage({
139139
onError: (err, commentId) => {
140140
console.error(
141141
`Error deleting comment ${commentId}. Rolling UI back`,
142-
err,
142+
err
143143
);
144144
alert("Error deleting comment");
145145
},
@@ -152,7 +152,7 @@ export default function PostPage({
152152
(commentId: number) => {
153153
deleteComment(commentId);
154154
},
155-
[deleteComment],
155+
[deleteComment]
156156
);
157157

158158
// Post new comment - with optimistic updates!
@@ -184,7 +184,7 @@ export default function PostPage({
184184
// Optimistically update to the new value
185185
queryClient.setQueryData(
186186
["comments", newComment.postId.toString()],
187-
(oldComments: any) => [...oldComments, newComment],
187+
(oldComments: any) => [...oldComments, newComment]
188188
);
189189

190190
// Return a context object with the snapshot value
@@ -195,7 +195,7 @@ export default function PostPage({
195195
onError: (err, newComment, context) => {
196196
queryClient.setQueryData(
197197
["comments", newComment.postId.toString()],
198-
context?.previousComments,
198+
context?.previousComments
199199
);
200200
console.error("Error posting comment. Rolling UI back", err);
201201
},

0 commit comments

Comments
 (0)