Skip to content

Commit 327deac

Browse files
fix(_official-blog-tutorial): fix useActionData/useLoaderData usage (#83)
1 parent cd681fd commit 327deac

File tree

15 files changed

+71
-138
lines changed

15 files changed

+71
-138
lines changed

_official-blog-tutorial/app/models/note.server.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import type { User, Note } from "@prisma/client";
22

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

5-
export type { Note } from "@prisma/client";
6-
75
export function getNote({
86
id,
97
userId,

_official-blog-tutorial/app/models/post.server.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Post } from "@prisma/client";
22

33
import { prisma } from "~/db.server";
4-
export type { Post };
54

65
export async function getPosts() {
76
return prisma.post.findMany();

_official-blog-tutorial/app/models/user.server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import type { Password, User } from "@prisma/client";
21
import bcrypt from "@node-rs/bcrypt";
2+
import type { Password, User } from "@prisma/client";
33

44
import { prisma } from "~/db.server";
55

_official-blog-tutorial/app/root.tsx

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import type {
2-
LinksFunction,
3-
LoaderFunction,
4-
MetaFunction,
5-
} from "@remix-run/node";
1+
import type { LinksFunction, LoaderArgs, MetaFunction } from "@remix-run/node";
62
import { json } from "@remix-run/node";
73
import {
84
Links,
@@ -26,14 +22,8 @@ export const meta: MetaFunction = () => ({
2622
viewport: "width=device-width,initial-scale=1",
2723
});
2824

29-
type LoaderData = {
30-
user: Awaited<ReturnType<typeof getUser>>;
31-
};
32-
33-
export const loader: LoaderFunction = async ({ request }) => {
34-
return json<LoaderData>({
35-
user: await getUser(request),
36-
});
25+
export const loader = async ({ request }: LoaderArgs) => {
26+
return json({ user: await getUser(request) });
3727
};
3828

3929
export default function App() {

_official-blog-tutorial/app/routes/healthcheck.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// learn more: https://fly.io/docs/reference/configuration/#services-http_checks
2-
import type { LoaderFunction } from "@remix-run/node";
2+
import type { LoaderArgs } from "@remix-run/node";
33

44
import { prisma } from "~/db.server";
55

6-
export const loader: LoaderFunction = async ({ request }) => {
6+
export const loader = async ({ request }: LoaderArgs) => {
77
const host =
88
request.headers.get("X-Forwarded-Host") ?? request.headers.get("host");
99

_official-blog-tutorial/app/routes/join.tsx

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import type {
2-
ActionFunction,
3-
LoaderFunction,
4-
MetaFunction,
5-
} from "@remix-run/node";
1+
import type { ActionArgs, LoaderArgs, MetaFunction } from "@remix-run/node";
62
import { json, redirect } from "@remix-run/node";
73
import { Form, Link, useActionData, useSearchParams } from "@remix-run/react";
84
import * as React from "react";
@@ -11,50 +7,48 @@ import { createUser, getUserByEmail } from "~/models/user.server";
117
import { getUserId, createUserSession } from "~/session.server";
128
import { safeRedirect, validateEmail } from "~/utils";
139

14-
export const loader: LoaderFunction = async ({ request }) => {
10+
export const loader = async ({ request }: LoaderArgs) => {
1511
const userId = await getUserId(request);
1612
if (userId) return redirect("/");
1713
return json({});
1814
};
1915

20-
interface ActionData {
21-
errors: {
22-
email?: string;
23-
password?: string;
24-
};
25-
}
26-
27-
export const action: ActionFunction = async ({ request }) => {
16+
export const action = async ({ request }: ActionArgs) => {
2817
const formData = await request.formData();
2918
const email = formData.get("email");
3019
const password = formData.get("password");
3120
const redirectTo = safeRedirect(formData.get("redirectTo"), "/");
3221

3322
if (!validateEmail(email)) {
34-
return json<ActionData>(
35-
{ errors: { email: "Email is invalid" } },
23+
return json(
24+
{ errors: { email: "Email is invalid", password: null } },
3625
{ status: 400 }
3726
);
3827
}
3928

4029
if (typeof password !== "string") {
41-
return json<ActionData>(
42-
{ errors: { password: "Password is required" } },
30+
return json(
31+
{ errors: { email: null, password: "Password is required" } },
4332
{ status: 400 }
4433
);
4534
}
4635

4736
if (password.length < 8) {
48-
return json<ActionData>(
49-
{ errors: { password: "Password is too short" } },
37+
return json(
38+
{ errors: { email: null, password: "Password is too short" } },
5039
{ status: 400 }
5140
);
5241
}
5342

5443
const existingUser = await getUserByEmail(email);
5544
if (existingUser) {
56-
return json<ActionData>(
57-
{ errors: { email: "A user already exists with this email" } },
45+
return json(
46+
{
47+
errors: {
48+
email: "A user already exists with this email",
49+
password: null,
50+
},
51+
},
5852
{ status: 400 }
5953
);
6054
}
@@ -78,7 +72,7 @@ export const meta: MetaFunction = () => {
7872
export default function Join() {
7973
const [searchParams] = useSearchParams();
8074
const redirectTo = searchParams.get("redirectTo") ?? undefined;
81-
const actionData = useActionData() as ActionData;
75+
const actionData = useActionData<typeof action>();
8276
const emailRef = React.useRef<HTMLInputElement>(null);
8377
const passwordRef = React.useRef<HTMLInputElement>(null);
8478

_official-blog-tutorial/app/routes/login.tsx

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import type {
2-
ActionFunction,
3-
LoaderFunction,
4-
MetaFunction,
5-
} from "@remix-run/node";
1+
import type { ActionArgs, LoaderArgs, MetaFunction } from "@remix-run/node";
62
import { json, redirect } from "@remix-run/node";
73
import { Form, Link, useActionData, useSearchParams } from "@remix-run/react";
84
import * as React from "react";
@@ -11,52 +7,45 @@ import { createUserSession, getUserId } from "~/session.server";
117
import { verifyLogin } from "~/models/user.server";
128
import { safeRedirect, validateEmail } from "~/utils";
139

14-
export const loader: LoaderFunction = async ({ request }) => {
10+
export const loader = async ({ request }: LoaderArgs) => {
1511
const userId = await getUserId(request);
1612
if (userId) return redirect("/");
1713
return json({});
1814
};
1915

20-
interface ActionData {
21-
errors?: {
22-
email?: string;
23-
password?: string;
24-
};
25-
}
26-
27-
export const action: ActionFunction = async ({ request }) => {
16+
export const action = async ({ request }: ActionArgs) => {
2817
const formData = await request.formData();
2918
const email = formData.get("email");
3019
const password = formData.get("password");
3120
const redirectTo = safeRedirect(formData.get("redirectTo"), "/notes");
3221
const remember = formData.get("remember");
3322

3423
if (!validateEmail(email)) {
35-
return json<ActionData>(
36-
{ errors: { email: "Email is invalid" } },
24+
return json(
25+
{ errors: { email: "Email is invalid", password: null } },
3726
{ status: 400 }
3827
);
3928
}
4029

4130
if (typeof password !== "string") {
42-
return json<ActionData>(
43-
{ errors: { password: "Password is required" } },
31+
return json(
32+
{ errors: { email: null, password: "Password is required" } },
4433
{ status: 400 }
4534
);
4635
}
4736

4837
if (password.length < 8) {
49-
return json<ActionData>(
50-
{ errors: { password: "Password is too short" } },
38+
return json(
39+
{ errors: { email: null, password: "Password is too short" } },
5140
{ status: 400 }
5241
);
5342
}
5443

5544
const user = await verifyLogin(email, password);
5645

5746
if (!user) {
58-
return json<ActionData>(
59-
{ errors: { email: "Invalid email or password" } },
47+
return json(
48+
{ errors: { email: "Invalid email or password", password: null } },
6049
{ status: 400 }
6150
);
6251
}
@@ -69,16 +58,14 @@ export const action: ActionFunction = async ({ request }) => {
6958
});
7059
};
7160

72-
export const meta: MetaFunction = () => {
73-
return {
74-
title: "Login",
75-
};
76-
};
61+
export const meta: MetaFunction = () => ({
62+
title: "Login",
63+
});
7764

7865
export default function LoginPage() {
7966
const [searchParams] = useSearchParams();
8067
const redirectTo = searchParams.get("redirectTo") || "/notes";
81-
const actionData = useActionData() as ActionData;
68+
const actionData = useActionData<typeof action>();
8269
const emailRef = React.useRef<HTMLInputElement>(null);
8370
const passwordRef = React.useRef<HTMLInputElement>(null);
8471

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 "~/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
};

_official-blog-tutorial/app/routes/notes.tsx

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

55
import { requireUserId } from "~/session.server";
66
import { useUser } from "~/utils";
77
import { getNoteListItems } from "~/models/note.server";
88

9-
type LoaderData = {
10-
noteListItems: Awaited<ReturnType<typeof getNoteListItems>>;
11-
};
12-
13-
export const loader: LoaderFunction = async ({ request }) => {
9+
export const loader = async ({ request }: LoaderArgs) => {
1410
const userId = await requireUserId(request);
1511
const noteListItems = await getNoteListItems({ userId });
16-
return json<LoaderData>({ noteListItems });
12+
return json({ noteListItems });
1713
};
1814

1915
export default function NotesPage() {
20-
const data = useLoaderData() as LoaderData;
16+
const data = useLoaderData<typeof loader>();
2117
const user = useUser();
2218

2319
return (

_official-blog-tutorial/app/routes/notes/$noteId.tsx

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,23 @@
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 { Form, useCatch, useLoaderData } from "@remix-run/react";
44
import invariant from "tiny-invariant";
55

6-
import type { Note } from "~/models/note.server";
7-
import { deleteNote } from "~/models/note.server";
8-
import { getNote } from "~/models/note.server";
6+
import { deleteNote, getNote } from "~/models/note.server";
97
import { requireUserId } from "~/session.server";
108

11-
type LoaderData = {
12-
note: Note;
13-
};
14-
15-
export const loader: LoaderFunction = async ({ request, params }) => {
9+
export const loader = async ({ params, request }: LoaderArgs) => {
1610
const userId = await requireUserId(request);
1711
invariant(params.noteId, "noteId not found");
1812

1913
const note = await getNote({ userId, id: params.noteId });
2014
if (!note) {
2115
throw new Response("Not Found", { status: 404 });
2216
}
23-
return json<LoaderData>({ note });
17+
return json({ note });
2418
};
2519

26-
export const action: ActionFunction = async ({ request, params }) => {
20+
export const action = async ({ params, request }: ActionArgs) => {
2721
const userId = await requireUserId(request);
2822
invariant(params.noteId, "noteId not found");
2923

@@ -33,7 +27,7 @@ export const action: ActionFunction = async ({ request, params }) => {
3327
};
3428

3529
export default function NoteDetailsPage() {
36-
const data = useLoaderData() as LoaderData;
30+
const data = useLoaderData<typeof loader>();
3731

3832
return (
3933
<div>

0 commit comments

Comments
 (0)