Closed yanachuwan9sm closed 10 months ago
Date | 進捗 | メモ |
---|---|---|
10/6 | 1:06:00min | 途中から Prisma 、データモデリングに寄り道して進捗遅め |
10/11 | 1:39:00min | |
10/12 | 1:44:00min | ほぼほぼ react-hook-form や デザインパターンに寄り道 |
10/13 | 1:48:00min | uploadthing とは? どんな仕組みなのか?で死ぬほど寄り道 |
10/20 | 2:32:00min | uploadthing の仕組みをひたすらソースコード見ながら理解してみる |
10/24 | 2:46:00min | 単純にそんなに進めてない |
10/25 | 3:26:00min | prisma少し復習しないと忘れてるかも。3:19:00辺りの型定義の必要性がわかってないかも。 |
10/26 | 3:43:00min | とりあえず0.5hぐらい進める。 |
10/31 | 4:53:00min |
revalidateTag
と server actions
使うことで UPDATE処理はAPI介さなくても出来る、、!?
原点回帰感ある。→ いたるところでこの操作を自由に行うと、操作に対してどこが更新されるのかが追えなくなる可能性はあるな。
https://zenn.dev/cybozu_frontend/articles/server-actions-and-revalidate
https://github.com/pingdotgg/uploadthing/blob/main/assets/Diagram.png
FileRouterを使用してNext.js APIルート(/api/uploadthing)を作成 👉 利用場面に応じて(認証が必要 or ファイルサイズ制限)エンドポイントを変えれるのいいね。
https://docs.uploadthing.com/api-reference/server#file-routes
// @/app/api/uploadthing/core.ts
import { createUploadthing, type FileRouter } from "uploadthing/next";
const f = createUploadthing();
const auth = (req: Request) => ({ id: "fakeId" }); // Fake auth function
export const ourFileRouter = {
// 独自のファイルルートを定義できる。
// 独自の認証を挟む事もできる(clerkやらnextauthやら)
profilePicture: f(["image"]).middleware(() => {}).onUploadComplete(async ()=> {}),
mediaPost: f(["image", "pdf", "video"]).middleware(() => {}).onUploadComplete(async ()=> {}),
} satisfies FileRouter;
export type OurFileRouter = typeof ourFileRouter;
普通に画像アップロード機能を入れるとなると、下記を全て自分でやらないといけないから、 サクッと画像アップロード機能を作りたい!という場合には良いサービスかもしれない。 (ただアップロードされた画像はURLを知っていれば誰でも閲覧する事が出来るようになってる。要改善。)
https://github.com/pingdotgg/uploadthing/blob/main/packages/uploadthing/src/next.ts
独自のファイルルートをどこで判定しているか? -> https://github.com/pingdotgg/uploadthing/blob/main/packages/uploadthing/src/internal/handler.ts#L146-L147
Tailwind CSS やら cva をうま〜く使うには? 以下のボイラープレートがめちゃめちゃ参考になる。
モーダル実装が参考になる。
zustand
が適しているなと思った。(JotaiはReactのライフサイクルの中で動いている(useState + Context)ため。)// use-modal-store.ts : 開閉に関する状態と処理はカスタムhook化
export type ModalType = 'createServer' | 'invite';
interface ModalStore {
type: ModalType | null;
isOpen: boolean;
onOpen: (type: ModalType, data?: ModalData) => void;
onClose: () => void;
}
export const useModal = create<ModalStore>((set) => ({
type: null,
isOpen: false,
onOpen: (type, data = {}) => set({ isOpen: true, type, data }),
onClose: () => set({ type: null, isOpen: false }),
}));
// modal-provider.tsx : モーダルコンポーネントを一元管理するproviderコンポーネント
export const ModalProvider = () => {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
if (!isMounted) return null;
return (
<>
<CreateServerModal />
<InviteModal />
</>
);
};
// create-server-modal.tsx / 「サーバー作成」の役割を持つモーダルコンポーネント
export const CreateServerModal = () => {
const { isOpen, onClose, type } = useModal();
const isModalOpen = isOpen && type === 'createServer';
// 省略
return (
<Dialog open={isModalOpen} onOpenChange={handleClose}>
<DialogContent className="bg-white text-black p-0 overflow-hidden">
・・・・
</DialogContent>
</Dialog>
);
};
// 呼び出し元
xport const NavigationAction = () => {
const { onOpen } = useModal();
return (
<div>
<ActionTooltip side="right" align="center" label="Add a server">
<button
className="group flex items-center"
onClick={() => onOpen('createServer')}
>
Button Click
</button>
</ActionTooltip>
</div>
);
};
// Root
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<ClerkProvider>
<html lang="en" suppressHydrationWarning>
<body className={cn(inter.className, 'bg-while dark:bg-[#313338]')}>
<NextThemeProvider>
<ModalProvider />
{children}
</NextThemeProvider>
</body>
</html>
</ClerkProvider>
);
}
この記事でも Recoil ではあるけど似たような実装をしてる
Next.js 13(App Router)、Socket.io、Prisma、Tailwind、MySQL をさらっ〜と手で動かして学ぶ。
video: https://www.youtube.com/watch?v=ZbX4Ok9YX94&t=2112s source code: https://github.com/AntonioErdeljac/next13-discord-clone