Skip to content

Commit

Permalink
fix(_official-blog-tutorial): fix useActionData/useLoaderData usage
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelDeBoey committed Nov 27, 2022
1 parent fa4b421 commit b5e5863
Show file tree
Hide file tree
Showing 15 changed files with 56 additions and 140 deletions.
2 changes: 0 additions & 2 deletions _official-blog-tutorial/app/models/note.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import type { User, Note } from "@prisma/client";

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

export type { Note } from "@prisma/client";

export function getNote({
id,
userId,
Expand Down
1 change: 0 additions & 1 deletion _official-blog-tutorial/app/models/post.server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Post } from "@prisma/client";

import { prisma } from "~/db.server";
export type { Post };

export async function getPosts() {
return prisma.post.findMany();
Expand Down
2 changes: 1 addition & 1 deletion _official-blog-tutorial/app/models/user.server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Password, User } from "@prisma/client";
import bcrypt from "@node-rs/bcrypt";
import type { Password, User } from "@prisma/client";

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

Expand Down
16 changes: 3 additions & 13 deletions _official-blog-tutorial/app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import type {
LinksFunction,
LoaderFunction,
MetaFunction,
} from "@remix-run/node";
import type { LinksFunction, LoaderArgs, MetaFunction } from "@remix-run/node";
import { json } from "@remix-run/node";
import {
Links,
Expand All @@ -26,14 +22,8 @@ export const meta: MetaFunction = () => ({
viewport: "width=device-width,initial-scale=1",
});

type LoaderData = {
user: Awaited<ReturnType<typeof getUser>>;
};

export const loader: LoaderFunction = async ({ request }) => {
return json<LoaderData>({
user: await getUser(request),
});
export const loader = async ({ request }: LoaderArgs) => {
return json({ user: await getUser(request) });
};

export default function App() {
Expand Down
4 changes: 2 additions & 2 deletions _official-blog-tutorial/app/routes/healthcheck.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// learn more: https://fly.io/docs/reference/configuration/#services-http_checks
import type { LoaderFunction } from "@remix-run/node";
import type { LoaderArgs } from "@remix-run/node";

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

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

Expand Down
30 changes: 8 additions & 22 deletions _official-blog-tutorial/app/routes/join.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import type {
ActionFunction,
LoaderFunction,
MetaFunction,
} from "@remix-run/node";
import type { ActionArgs, LoaderArgs, MetaFunction } from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
import { Form, Link, useActionData, useSearchParams } from "@remix-run/react";
import * as React from "react";
Expand All @@ -11,49 +7,39 @@ import { createUser, getUserByEmail } from "~/models/user.server";
import { getUserId, createUserSession } from "~/session.server";
import { safeRedirect, validateEmail } from "~/utils";

export const loader: LoaderFunction = async ({ request }) => {
export const loader = async ({ request }: LoaderArgs) => {
const userId = await getUserId(request);
if (userId) return redirect("/");
return json({});
};

interface ActionData {
errors: {
email?: string;
password?: string;
};
}

export const action: ActionFunction = async ({ request }) => {
export const action = async ({ request }: ActionArgs) => {
const formData = await request.formData();
const email = formData.get("email");
const password = formData.get("password");
const redirectTo = safeRedirect(formData.get("redirectTo"), "/");

if (!validateEmail(email)) {
return json<ActionData>(
{ errors: { email: "Email is invalid" } },
{ status: 400 }
);
return json({ errors: { email: "Email is invalid" } }, { status: 400 });
}

if (typeof password !== "string") {
return json<ActionData>(
return json(
{ errors: { password: "Password is required" } },
{ status: 400 }
);
}

if (password.length < 8) {
return json<ActionData>(
return json(
{ errors: { password: "Password is too short" } },
{ status: 400 }
);
}

const existingUser = await getUserByEmail(email);
if (existingUser) {
return json<ActionData>(
return json(
{ errors: { email: "A user already exists with this email" } },
{ status: 400 }
);
Expand All @@ -78,7 +64,7 @@ export const meta: MetaFunction = () => {
export default function Join() {
const [searchParams] = useSearchParams();
const redirectTo = searchParams.get("redirectTo") ?? undefined;
const actionData = useActionData() as ActionData;
const actionData = useActionData<typeof action>();
const emailRef = React.useRef<HTMLInputElement>(null);
const passwordRef = React.useRef<HTMLInputElement>(null);

Expand Down
38 changes: 11 additions & 27 deletions _official-blog-tutorial/app/routes/login.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import type {
ActionFunction,
LoaderFunction,
MetaFunction,
} from "@remix-run/node";
import type { ActionArgs, LoaderArgs, MetaFunction } from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
import { Form, Link, useActionData, useSearchParams } from "@remix-run/react";
import * as React from "react";
Expand All @@ -11,42 +7,32 @@ import { createUserSession, getUserId } from "~/session.server";
import { verifyLogin } from "~/models/user.server";
import { safeRedirect, validateEmail } from "~/utils";

export const loader: LoaderFunction = async ({ request }) => {
export const loader = async ({ request }: LoaderArgs) => {
const userId = await getUserId(request);
if (userId) return redirect("/");
return json({});
};

interface ActionData {
errors?: {
email?: string;
password?: string;
};
}

export const action: ActionFunction = async ({ request }) => {
export const action = async ({ request }: ActionArgs) => {
const formData = await request.formData();
const email = formData.get("email");
const password = formData.get("password");
const redirectTo = safeRedirect(formData.get("redirectTo"), "/notes");
const remember = formData.get("remember");

if (!validateEmail(email)) {
return json<ActionData>(
{ errors: { email: "Email is invalid" } },
{ status: 400 }
);
return json({ errors: { email: "Email is invalid" } }, { status: 400 });
}

if (typeof password !== "string") {
return json<ActionData>(
return json(
{ errors: { password: "Password is required" } },
{ status: 400 }
);
}

if (password.length < 8) {
return json<ActionData>(
return json(
{ errors: { password: "Password is too short" } },
{ status: 400 }
);
Expand All @@ -55,7 +41,7 @@ export const action: ActionFunction = async ({ request }) => {
const user = await verifyLogin(email, password);

if (!user) {
return json<ActionData>(
return json(
{ errors: { email: "Invalid email or password" } },
{ status: 400 }
);
Expand All @@ -69,16 +55,14 @@ export const action: ActionFunction = async ({ request }) => {
});
};

export const meta: MetaFunction = () => {
return {
title: "Login",
};
};
export const meta: MetaFunction = () => ({
title: "Login",
});

export default function LoginPage() {
const [searchParams] = useSearchParams();
const redirectTo = searchParams.get("redirectTo") || "/notes";
const actionData = useActionData() as ActionData;
const actionData = useActionData<typeof action>();
const emailRef = React.useRef<HTMLInputElement>(null);
const passwordRef = React.useRef<HTMLInputElement>(null);

Expand Down
6 changes: 3 additions & 3 deletions _official-blog-tutorial/app/routes/logout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { ActionFunction, LoaderFunction } from "@remix-run/node";
import type { ActionArgs } from "@remix-run/node";
import { redirect } from "@remix-run/node";

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

export const action: ActionFunction = async ({ request }) => {
export const action = async ({ request }: ActionArgs) => {
return logout(request);
};

export const loader: LoaderFunction = async () => {
export const loader = async () => {
return redirect("/");
};
12 changes: 4 additions & 8 deletions _official-blog-tutorial/app/routes/notes.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
import type { LoaderFunction } from "@remix-run/node";
import type { LoaderArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { Form, Link, NavLink, Outlet, useLoaderData } from "@remix-run/react";

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

type LoaderData = {
noteListItems: Awaited<ReturnType<typeof getNoteListItems>>;
};

export const loader: LoaderFunction = async ({ request }) => {
export const loader = async ({ request }: LoaderArgs) => {
const userId = await requireUserId(request);
const noteListItems = await getNoteListItems({ userId });
return json<LoaderData>({ noteListItems });
return json({ noteListItems });
};

export default function NotesPage() {
const data = useLoaderData() as LoaderData;
const data = useLoaderData<typeof loader>();
const user = useUser();

return (
Expand Down
18 changes: 6 additions & 12 deletions _official-blog-tutorial/app/routes/notes/$noteId.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,23 @@
import type { ActionFunction, LoaderFunction } from "@remix-run/node";
import type { ActionArgs, LoaderArgs } from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
import { Form, useCatch, useLoaderData } from "@remix-run/react";
import invariant from "tiny-invariant";

import type { Note } from "~/models/note.server";
import { deleteNote } from "~/models/note.server";
import { getNote } from "~/models/note.server";
import { deleteNote, getNote } from "~/models/note.server";
import { requireUserId } from "~/session.server";

type LoaderData = {
note: Note;
};

export const loader: LoaderFunction = async ({ request, params }) => {
export const loader = async ({ params, request }: LoaderArgs) => {
const userId = await requireUserId(request);
invariant(params.noteId, "noteId not found");

const note = await getNote({ userId, id: params.noteId });
if (!note) {
throw new Response("Not Found", { status: 404 });
}
return json<LoaderData>({ note });
return json({ note });
};

export const action: ActionFunction = async ({ request, params }) => {
export const action = async ({ params, request }: ActionArgs) => {
const userId = await requireUserId(request);
invariant(params.noteId, "noteId not found");

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

export default function NoteDetailsPage() {
const data = useLoaderData() as LoaderData;
const data = useLoaderData<typeof loader>();

return (
<div>
Expand Down
23 changes: 5 additions & 18 deletions _official-blog-tutorial/app/routes/notes/new.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,25 @@
import Alert from "@reach/alert";
import type { ActionFunction } from "@remix-run/node";
import type { ActionArgs } from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
import { Form, useActionData } from "@remix-run/react";
import * as React from "react";

import { createNote } from "~/models/note.server";
import { requireUserId } from "~/session.server";

type ActionData = {
errors?: {
title?: string;
body?: string;
};
};

export const action: ActionFunction = async ({ request }) => {
export const action = async ({ request }: ActionArgs) => {
const userId = await requireUserId(request);

const formData = await request.formData();
const title = formData.get("title");
const body = formData.get("body");

if (typeof title !== "string" || title.length === 0) {
return json<ActionData>(
{ errors: { title: "Title is required" } },
{ status: 400 }
);
return json({ errors: { title: "Title is required" } }, { status: 400 });
}

if (typeof body !== "string" || body.length === 0) {
return json<ActionData>(
{ errors: { body: "Body is required" } },
{ status: 400 }
);
return json({ errors: { body: "Body is required" } }, { status: 400 });
}

const note = await createNote({ title, body, userId });
Expand All @@ -41,7 +28,7 @@ export const action: ActionFunction = async ({ request }) => {
};

export default function NewNotePage() {
const actionData = useActionData() as ActionData;
const actionData = useActionData<typeof action>();
const titleRef = React.useRef<HTMLInputElement>(null);
const bodyRef = React.useRef<HTMLTextAreaElement>(null);

Expand Down
11 changes: 4 additions & 7 deletions _official-blog-tutorial/app/routes/posts/$slug.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import type { LoaderFunction } from "@remix-run/node";
import type { LoaderArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { marked } from "marked";
import invariant from "tiny-invariant";

import { getPost } from "~/models/post.server";
import type { Post } from "~/models/post.server";

type LoaderData = { post: Post; html: string };

export const loader: LoaderFunction = async ({ params }) => {
export const loader = async ({ params }: LoaderArgs) => {
invariant(params.slug, `params.slug is required`);

const post = await getPost(params.slug);
invariant(post, `Post not found: ${params.slug}`);

const html = marked(post.markdown);
return json<LoaderData>({ post, html });
return json({ post, html });
};

export default function PostSlug() {
const { post, html } = useLoaderData() as LoaderData;
const { post, html } = useLoaderData<typeof loader>();
return (
<main className="mx-auto max-w-4xl">
<h1 className="my-6 border-b-2 text-center text-3xl">{post.title}</h1>
Expand Down
Loading

0 comments on commit b5e5863

Please sign in to comment.