Skip to content

Commit 7eeb2a5

Browse files
fix(_official-jokes): fix useActionData/useLoaderData usage (#84)
1 parent 327deac commit 7eeb2a5

File tree

8 files changed

+72
-108
lines changed

8 files changed

+72
-108
lines changed

_official-jokes/app/routes/jokes.tsx

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { LinksFunction, LoaderFunction } from "@remix-run/node";
1+
import type { LinksFunction, LoaderArgs } from "@remix-run/node";
22
import { json } from "@remix-run/node";
33
import { Form, Link, Outlet, useLoaderData } from "@remix-run/react";
44

@@ -7,12 +7,7 @@ import { getUser } from "~/utils/session.server";
77

88
import stylesUrl from "../styles/jokes.css";
99

10-
type LoaderData = {
11-
user: Awaited<ReturnType<typeof getUser>>;
12-
jokeListItems: Array<{ id: string; name: string }>;
13-
};
14-
15-
export const loader: LoaderFunction = async ({ request }) => {
10+
export const loader = async ({ request }: LoaderArgs) => {
1611
const user = await getUser(request);
1712

1813
// in the official deployed version of the app, we don't want to deploy
@@ -26,20 +21,18 @@ export const loader: LoaderFunction = async ({ request }) => {
2621
})
2722
: [];
2823

29-
const data: LoaderData = {
24+
return json({
3025
jokeListItems,
3126
user,
32-
};
33-
34-
return json(data);
27+
});
3528
};
3629

37-
export const links: LinksFunction = () => {
38-
return [{ rel: "stylesheet", href: stylesUrl }];
39-
};
30+
export const links: LinksFunction = () => [
31+
{ rel: "stylesheet", href: stylesUrl },
32+
];
4033

4134
export default function JokesScreen() {
42-
const data = useLoaderData<LoaderData>();
35+
const data = useLoaderData<typeof loader>();
4336

4437
return (
4538
<div className="jokes-layout">

_official-jokes/app/routes/jokes/$jokeId.tsx

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,12 @@
1-
import type { Joke } from "@prisma/client";
2-
import type {
3-
ActionFunction,
4-
LoaderFunction,
5-
MetaFunction,
6-
} from "@remix-run/node";
1+
import type { ActionArgs, LoaderArgs, MetaFunction } from "@remix-run/node";
72
import { json, redirect } from "@remix-run/node";
83
import { useCatch, useLoaderData, useParams } from "@remix-run/react";
94

105
import { db } from "~/utils/db.server";
116
import { getUserId, requireUserId } from "~/utils/session.server";
127
import { JokeDisplay } from "~/components/joke";
138

14-
export const meta: MetaFunction = ({
15-
data,
16-
}: {
17-
data: LoaderData | undefined;
18-
}) => {
9+
export const meta: MetaFunction<typeof loader> = ({ data }) => {
1910
if (!data) {
2011
return {
2112
title: "No joke",
@@ -28,19 +19,16 @@ export const meta: MetaFunction = ({
2819
};
2920
};
3021

31-
type LoaderData = { joke: Joke; isOwner: boolean };
32-
33-
export const loader: LoaderFunction = async ({ request, params }) => {
22+
export const loader = async ({ params, request }: LoaderArgs) => {
3423
const userId = await getUserId(request);
3524
const joke = await db.joke.findUnique({ where: { id: params.jokeId } });
3625
if (!joke) {
3726
throw new Response("What a joke! Not found.", { status: 404 });
3827
}
39-
const data: LoaderData = { joke, isOwner: userId === joke.jokesterId };
40-
return json(data);
28+
return json({ joke, isOwner: userId === joke.jokesterId });
4129
};
4230

43-
export const action: ActionFunction = async ({ request, params }) => {
31+
export const action = async ({ params, request }: ActionArgs) => {
4432
const form = await request.formData();
4533
if (form.get("intent") !== "delete") {
4634
throw new Response(`The intent ${form.get("intent")} is not supported`, {
@@ -64,7 +52,7 @@ export const action: ActionFunction = async ({ request, params }) => {
6452
};
6553

6654
export default function JokeRoute() {
67-
const data = useLoaderData<LoaderData>();
55+
const data = useLoaderData<typeof loader>();
6856

6957
return <JokeDisplay joke={data.joke} isOwner={data.isOwner} />;
7058
}

_official-jokes/app/routes/jokes/index.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
import type { Joke } from "@prisma/client";
2-
import type { LoaderFunction } from "@remix-run/node";
1+
import type { LoaderArgs } from "@remix-run/node";
32
import { json } from "@remix-run/node";
43
import { Link, useCatch, useLoaderData } from "@remix-run/react";
54

65
import { db } from "~/utils/db.server";
76
import { getUserId } from "~/utils/session.server";
87

9-
type LoaderData = { randomJoke: Joke };
10-
11-
export const loader: LoaderFunction = async ({ request }) => {
8+
export const loader = async ({ request }: LoaderArgs) => {
129
const userId = await getUserId(request);
1310
const count = await db.joke.count();
1411
const randomRowNumber = Math.floor(Math.random() * count);
@@ -27,12 +24,11 @@ export const loader: LoaderFunction = async ({ request }) => {
2724
if (!randomJoke) {
2825
throw new Response("No jokes to be found!", { status: 404 });
2926
}
30-
const data: LoaderData = { randomJoke };
31-
return json(data);
27+
return json({ randomJoke });
3228
};
3329

3430
export default function JokesIndexRoute() {
35-
const data = useLoaderData<LoaderData>();
31+
const data = useLoaderData<typeof loader>();
3632

3733
return (
3834
<div>

_official-jokes/app/routes/jokes/new.tsx

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ActionFunction, LoaderFunction } from "@remix-run/node";
1+
import type { ActionArgs, LoaderArgs } from "@remix-run/node";
22
import { json, redirect } from "@remix-run/node";
33
import {
44
Form,
@@ -10,9 +10,10 @@ import {
1010

1111
import { JokeDisplay } from "~/components/joke";
1212
import { db } from "~/utils/db.server";
13+
import { badRequest } from "~/utils/request.server";
1314
import { getUserId, requireUserId } from "~/utils/session.server";
1415

15-
export const loader: LoaderFunction = async ({ request }) => {
16+
export const loader = async ({ request }: LoaderArgs) => {
1617
const userId = await getUserId(request);
1718
if (!userId) {
1819
throw new Response("Unauthorized", { status: 401 });
@@ -32,30 +33,18 @@ function validateJokeName(name: string) {
3233
}
3334
}
3435

35-
type ActionData = {
36-
formError?: string;
37-
fieldErrors?: { name: string | undefined; content: string | undefined };
38-
fields?: {
39-
name: string;
40-
content: string;
41-
};
42-
};
43-
44-
/**
45-
* This helper function gives us typechecking for our ActionData return
46-
* statements, while still returning the accurate HTTP status, 400 Bad Request,
47-
* to the client.
48-
*/
49-
const badRequest = (data: ActionData) => json(data, { status: 400 });
50-
51-
export const action: ActionFunction = async ({ request }) => {
36+
export const action = async ({ request }: ActionArgs) => {
5237
const userId = await requireUserId(request);
5338

5439
const form = await request.formData();
5540
const name = form.get("name");
5641
const content = form.get("content");
5742
if (typeof name !== "string" || typeof content !== "string") {
58-
return badRequest({ formError: `Form not submitted correctly.` });
43+
return badRequest({
44+
fieldErrors: null,
45+
fields: null,
46+
formError: `Form not submitted correctly.`,
47+
});
5948
}
6049

6150
const fieldErrors = {
@@ -64,7 +53,7 @@ export const action: ActionFunction = async ({ request }) => {
6453
};
6554
const fields = { name, content };
6655
if (Object.values(fieldErrors).some(Boolean)) {
67-
return badRequest({ fieldErrors, fields });
56+
return badRequest({ fieldErrors, fields, formError: null });
6857
}
6958

7059
const joke = await db.joke.create({
@@ -74,7 +63,7 @@ export const action: ActionFunction = async ({ request }) => {
7463
};
7564

7665
export default function NewJokeRoute() {
77-
const actionData = useActionData<ActionData>();
66+
const actionData = useActionData<typeof action>();
7867
const transition = useTransition();
7968

8069
if (transition.submission) {

_official-jokes/app/routes/jokes[.]rss.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import type { LoaderFunction } from "@remix-run/node";
1+
import type { LoaderArgs } from "@remix-run/node";
22

33
import { db } from "~/utils/db.server";
44

5-
export const loader: LoaderFunction = async ({ request }) => {
5+
export const loader = async ({ request }: LoaderArgs) => {
66
const jokes = await db.joke.findMany({
77
take: 100,
88
orderBy: { createdAt: "desc" },

_official-jokes/app/routes/login.tsx

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,19 @@
1-
import type {
2-
ActionFunction,
3-
LinksFunction,
4-
MetaFunction,
5-
} from "@remix-run/node";
6-
import { json } from "@remix-run/node";
7-
import { Form, Link, useActionData, useSearchParams } from "@remix-run/react";
1+
import type { ActionArgs, LinksFunction, MetaFunction } from "@remix-run/node";
2+
import { Link, useActionData, useSearchParams } from "@remix-run/react";
83

9-
import { login, createUserSession, register } from "~/utils/session.server";
4+
import stylesUrl from "~/styles/login.css";
105
import { db } from "~/utils/db.server";
6+
import { badRequest } from "~/utils/request.server";
7+
import { createUserSession, login, register } from "~/utils/session.server";
118

12-
import stylesUrl from "../styles/login.css";
9+
export const meta: MetaFunction = () => ({
10+
description: "Login to submit your own jokes to Remix Jokes!",
11+
title: "Remix Jokes | Login",
12+
});
1313

14-
export const meta: MetaFunction = () => {
15-
return {
16-
title: "Remix Jokes | Login",
17-
description: "Login to submit your own jokes to Remix Jokes!",
18-
};
19-
};
20-
21-
export const links: LinksFunction = () => {
22-
return [{ rel: "stylesheet", href: stylesUrl }];
23-
};
14+
export const links: LinksFunction = () => [
15+
{ rel: "stylesheet", href: stylesUrl },
16+
];
2417

2518
function validateUsername(username: unknown) {
2619
if (typeof username !== "string" || username.length < 3) {
@@ -34,28 +27,15 @@ function validatePassword(password: unknown) {
3427
}
3528
}
3629

37-
function validateUrl(url: any) {
30+
function validateUrl(url: string) {
3831
const urls = ["/jokes", "/", "https://remix.run"];
3932
if (urls.includes(url)) {
4033
return url;
4134
}
4235
return "/jokes";
4336
}
4437

45-
type ActionData = {
46-
formError?: string;
47-
fieldErrors?: { username: string | undefined; password: string | undefined };
48-
fields?: { loginType: string; username: string; password: string };
49-
};
50-
51-
/**
52-
* This helper function gives us typechecking for our ActionData return
53-
* statements, while still returning the accurate HTTP status, 400 Bad Request,
54-
* to the client.
55-
*/
56-
const badRequest = (data: ActionData) => json(data, { status: 400 });
57-
58-
export const action: ActionFunction = async ({ request }) => {
38+
export const action = async ({ request }: ActionArgs) => {
5939
const form = await request.formData();
6040
const loginType = form.get("loginType");
6141
const username = form.get("username");
@@ -67,7 +47,11 @@ export const action: ActionFunction = async ({ request }) => {
6747
typeof password !== "string" ||
6848
typeof redirectTo !== "string"
6949
) {
70-
return badRequest({ formError: `Form not submitted correctly.` });
50+
return badRequest({
51+
fieldErrors: null,
52+
fields: null,
53+
formError: `Form not submitted correctly.`,
54+
});
7155
}
7256

7357
const fields = { loginType, username, password };
@@ -76,14 +60,15 @@ export const action: ActionFunction = async ({ request }) => {
7660
password: validatePassword(password),
7761
};
7862
if (Object.values(fieldErrors).some(Boolean)) {
79-
return badRequest({ fieldErrors, fields });
63+
return badRequest({ fieldErrors, fields, formError: null });
8064
}
8165

8266
switch (loginType) {
8367
case "login": {
8468
const user = await login({ username, password });
8569
if (!user) {
8670
return badRequest({
71+
fieldErrors: null,
8772
fields,
8873
formError: `Username/Password combination is incorrect`,
8974
});
@@ -94,33 +79,39 @@ export const action: ActionFunction = async ({ request }) => {
9479
const userExists = await db.user.findFirst({ where: { username } });
9580
if (userExists) {
9681
return badRequest({
82+
fieldErrors: null,
9783
fields,
9884
formError: `User with username ${username} already exists`,
9985
});
10086
}
10187
const user = await register({ username, password });
10288
if (!user) {
10389
return badRequest({
90+
fieldErrors: null,
10491
fields,
10592
formError: `Something went wrong trying to create a new user.`,
10693
});
10794
}
10895
return createUserSession(user.id, redirectTo);
10996
}
11097
default: {
111-
return badRequest({ fields, formError: `Login type invalid` });
98+
return badRequest({
99+
fieldErrors: null,
100+
fields,
101+
formError: `Login type invalid`,
102+
});
112103
}
113104
}
114105
};
115106

116107
export default function Login() {
117-
const actionData = useActionData<ActionData>();
108+
const actionData = useActionData<typeof action>();
118109
const [searchParams] = useSearchParams();
119110
return (
120111
<div className="container">
121112
<div className="content" data-light="">
122113
<h1>Login</h1>
123-
<Form method="post">
114+
<form method="post">
124115
<input
125116
type="hidden"
126117
name="redirectTo"
@@ -204,7 +195,7 @@ export default function Login() {
204195
<button type="submit" className="button">
205196
Submit
206197
</button>
207-
</Form>
198+
</form>
208199
</div>
209200
<div className="links">
210201
<ul>

_official-jokes/app/routes/logout.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import type { ActionFunction, LoaderFunction } from "@remix-run/node";
1+
import type { ActionArgs } from "@remix-run/node";
22
import { redirect } from "@remix-run/node";
33

44
import { logout } from "~/utils/session.server";
55

6-
export const action: ActionFunction = async ({ request }) => {
6+
export const action = async ({ request }: ActionArgs) => {
77
return logout(request);
88
};
99

10-
export const loader: LoaderFunction = async () => {
10+
export const loader = async () => {
1111
return redirect("/");
1212
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { json } from "@remix-run/node";
2+
3+
/**
4+
* This helper function helps us returning the accurate HTTP status,
5+
* 400 Bad Request, to the client.
6+
*/
7+
export const badRequest = <T>(data: T) => json<T>(data, { status: 400 });

0 commit comments

Comments
 (0)