Skip to content
This repository was archived by the owner on Feb 23, 2025. It is now read-only.

Commit

Permalink
refactor: simplify root loader (#487)
Browse files Browse the repository at this point in the history
  • Loading branch information
hi-ogawa authored Aug 22, 2023
1 parent 1b1a6dd commit 541f613
Show file tree
Hide file tree
Showing 10 changed files with 44 additions and 43 deletions.
8 changes: 6 additions & 2 deletions app/root.server.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { TT } from "./db/drizzle-client.server";
import { ctx_currentUser } from "./server/request-context/session";
import { RootLoaderData } from "./utils/loader-utils";
import { wrapLoader } from "./utils/loader-utils.server";

export type LoaderData = {
currentUser?: TT["users"];
};

export const loader = wrapLoader(async () => {
const loaderData: RootLoaderData = {
const loaderData: LoaderData = {
currentUser: await ctx_currentUser(),
};
return loaderData;
Expand Down
7 changes: 4 additions & 3 deletions app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,17 @@ import {
encodeFlashMessage,
useFlashMessageHandler,
} from "./utils/flash-message";
import { useRootLoaderData } from "./utils/loader-utils";
import { useLoaderDataExtra } from "./utils/loader-utils";
import { cls } from "./utils/misc";
import { navigateRefresh } from "./utils/misc-client";
import type { PageHandle } from "./utils/page-handle";
import { QueryClientWrapper } from "./utils/react-query-utils";
import { ToastWrapper } from "./utils/toast-utils";

export { loader } from "./root.server";
import { LoaderData } from "./root.server";

// no need to revalidate `currentUser` since app refreshes on user session change (signin/signout)
// for now, we don't revalidate `currentUser` and rely on page refresh on signin/signout
export const shouldRevalidate: ShouldRevalidateFunction = () => false;

export default function DefaultComponent() {
Expand Down Expand Up @@ -78,7 +79,7 @@ function RootWrapper(props: React.PropsWithChildren) {
}

function Root() {
const data = useRootLoaderData();
const data = useLoaderDataExtra() as LoaderData;
useFlashMessageHandler();

// `PageHandle` of the leaf compoment
Expand Down
4 changes: 3 additions & 1 deletion app/routes/index.server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { wrapLoader } from "../utils/loader-utils.server";
import { PAGINATION_PARAMS_SCHEMA } from "../utils/pagination";
import { VideosLoaderData, getVideosLoaderData } from "./videos/index.server";

export type LoaderData = VideosLoaderData;

export const loader = wrapLoader(async () => {
const query = PAGINATION_PARAMS_SCHEMA.parse(ctx_get().urlQuery);
const loaderData: VideosLoaderData = await getVideosLoaderData(query);
const loaderData: LoaderData = await getVideosLoaderData(query);
return loaderData;
});
4 changes: 2 additions & 2 deletions app/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { useLoaderDataExtra } from "../utils/loader-utils";
import type { PageHandle } from "../utils/page-handle";
import { VideoListComponent } from "./videos";
import type { VideosLoaderData } from "./videos/index.server";

export { loader } from "./index.server";
import type { LoaderData } from "./index.server";

export const handle: PageHandle = {
navBarTitle: () => "Examples",
};

export default function DefaultComponent() {
const data = useLoaderDataExtra() as VideosLoaderData;
const data = useLoaderDataExtra() as LoaderData;
return <VideoListComponent {...data} />;
}
7 changes: 5 additions & 2 deletions app/routes/videos/$id.server.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { E, T, selectOne } from "../../db/drizzle-client.server";
import { E, T, TT, selectOne } from "../../db/drizzle-client.server";
import type { VideoTable } from "../../db/models";
import { ROUTE_DEF } from "../../misc/routes";
import { ctx_currentUser } from "../../server/request-context/session";
import { ctx_get } from "../../server/request-context/storage";
import {
assertOrRespond,
Expand All @@ -9,15 +10,17 @@ import {
} from "../../utils/loader-utils.server";

export type LoaderData = {
currentUser?: TT["users"];
video: VideoTable;
};

export const loader = wrapLoader(async () => {
const currentUser = await ctx_currentUser();
const params = unwrapZodResultOrRespond(
ROUTE_DEF["/videos/$id"].params.safeParse(ctx_get().params)
);
const video = await selectOne(T.videos, E.eq(T.videos.id, params.id));
assertOrRespond(video);
const loaderData: LoaderData = { video };
const loaderData: LoaderData = { video, currentUser };
return loaderData;
});
11 changes: 4 additions & 7 deletions app/routes/videos/$id.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
disableUrlQueryRevalidation,
useLeafLoaderData,
useLoaderDataExtra,
useRootLoaderData,
useTypedUrlQuery,
} from "../../utils/loader-utils";
import { cls, none } from "../../utils/misc";
Expand All @@ -50,9 +49,8 @@ export const handle: PageHandle = {
};

export default function DeafultComponent() {
const { currentUser } = useRootLoaderData();
const data = useLoaderDataExtra() as LoaderData;
return <PageComponent currentUser={currentUser} {...data} />;
const loaderData = useLoaderDataExtra() as LoaderData;
return <PageComponent {...loaderData} />;
}

export function findCurrentEntry(
Expand Down Expand Up @@ -140,7 +138,7 @@ function PageComponent({
// mutate query cache instead of refetch
queryClient.setQueryData(
bookmarkEntriesQueryOptions.queryKey,
(prev) => [...(prev as TT["bookmarkEntries"][]), newBookmark]
(prev: unknown) => [...(prev as TT["bookmarkEntries"][]), newBookmark]
);
}
},
Expand Down Expand Up @@ -721,8 +719,7 @@ function extractBookmarkSelection(
//

function NavBarMenuComponent() {
const { currentUser } = useRootLoaderData();
const { video } = useLeafLoaderData() as LoaderData;
const { currentUser, video } = useLeafLoaderData() as LoaderData;
const [autoScrollState, toggleAutoScrollState] = useAutoScrollState();
const [repeatingEntries, setRepeatingEntries] = useRepeatingEntries();
const [highlightBookmark, setHighlightBookmark] = useAtom(
Expand Down
21 changes: 14 additions & 7 deletions app/routes/videos/index.server.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { E, T, db, toPaginationResult } from "../../db/drizzle-client.server";
import type { VideoTable } from "../../db/models";
import {
E,
T,
TT,
db,
toPaginationResult,
} from "../../db/drizzle-client.server";
import { ctx_get } from "../../server/request-context/storage";
import {
ctx_requireUserOrRedirect,
Expand All @@ -12,8 +17,9 @@ import {
} from "../../utils/pagination";

export interface VideosLoaderData {
videos: VideoTable[];
videos: TT["videos"][];
pagination: PaginationMetadata;
currentUser?: TT["users"];
}

export async function getVideosLoaderData(
Expand All @@ -34,9 +40,10 @@ export async function getVideosLoaderData(
export const loader = wrapLoader(async () => {
const user = await ctx_requireUserOrRedirect();
const query = PAGINATION_PARAMS_SCHEMA.parse(ctx_get().urlQuery);
const loaderData: VideosLoaderData = await getVideosLoaderData(
query,
user.id
);
const data = await getVideosLoaderData(query, user.id);
const loaderData: VideosLoaderData = {
...data,
currentUser: user,
};
return loaderData;
});
2 changes: 2 additions & 0 deletions app/routes/videos/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe("videos/index.loader", () => {
expect(
z
.object({
currentUser: zSnapshotType,
videos: z
.object({
id: zSnapshotType,
Expand All @@ -36,6 +37,7 @@ describe("videos/index.loader", () => {
.parse(loaderData)
).toMatchInlineSnapshot(`
{
"currentUser": "[Object]",
"pagination": {
"page": 1,
"perPage": 20,
Expand Down
13 changes: 4 additions & 9 deletions app/routes/videos/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ import { useModal } from "../../components/modal";
import type { DeckTable, UserTable, VideoTable } from "../../db/models";
import { R } from "../../misc/routes";
import { rpcClientQuery } from "../../trpc/client";
import {
useLoaderDataExtra,
useRootLoaderData,
} from "../../utils/loader-utils";
import { useLoaderDataExtra } from "../../utils/loader-utils";
import type { PageHandle } from "../../utils/page-handle";
import { toastInfo } from "../../utils/toast-utils";

Expand All @@ -34,18 +31,16 @@ export const handle: PageHandle = {
};

export default function DefaultComponent() {
const { currentUser } = useRootLoaderData();
const data = useLoaderDataExtra() as VideosLoaderData;
return <VideoListComponent {...data} currentUser={currentUser} />;
return <VideoListComponent {...data} />;
}

// reused for routes/index.tsx
export function VideoListComponent({
videos,
pagination,
currentUser,
}: VideosLoaderData & {
currentUser?: UserTable;
}) {
}: VideosLoaderData) {
return (
<>
<div className="w-full flex justify-center">
Expand Down
10 changes: 0 additions & 10 deletions app/utils/loader-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,8 @@ import {
} from "@remix-run/react";
import React from "react";
import type { z } from "zod";
import type { UserTable } from "../db/models";
import { JSON_EXTRA } from "./json-extra";

export interface RootLoaderData {
currentUser?: UserTable;
}

export function useRootLoaderData(): RootLoaderData {
const [{ data }] = useMatches();
return React.useMemo(() => JSON_EXTRA.deserialize(data), [data]);
}

export function useLeafLoaderData(): unknown {
const [{ data }] = useMatches().slice(-1);
return React.useMemo(() => JSON_EXTRA.deserialize(data), [data]);
Expand Down

0 comments on commit 541f613

Please sign in to comment.