【Youtube】「Full Stack Airbnb Clone with Next.js 13」をやる
YouTube
最近上がっているやつなので、ちょこちょこやってみる。
8時間40分あるから終わるから、手を動かしたら実際20時間超えそう。
完成品のgithubリポジトリ
使用する技術
- Next.js 13 App Router
- React
- Tailwind CSS
- Prisma
- MongoDB
- NextAuth 2023
ハイドレーションエラー対策
原因とその対策(by Chat GPT4)
クライアント側でレンダリングされたHTMLが、サーバーサイドでレンダリングされたHTMLと一致しないことを示しているエラー。
Next.jsがサーバーサイドレンダリング(SSR)とクライアントサイドレンダリング(CSR)の両方をサポートしているために発生する可能性がある。
このエラーの一般的な原因は次のとおり
クライアントとサーバーの状態の不一致:
状態がクライアントとサーバーの間で異なる場合、レンダリングされたHTMLが一致しない可能性があります。これを解決するには、状態を同期させるか、クライアント側でのみ状態を使用するようにする必要があります。
サーバーでのみ使用される機能やライブラリ:
サーバーでのみ実行されるコードがクライアント側で実行されない場合、HTMLが一致しない可能性があります。この問題を解決するには、クライアント側で適切にレンダリングされるようにコードを修正するか、サーバーでのみ使用されるコードをクライアント側でも使用できるようにする必要があります。
クライアントでのみ使用される機能やライブラリ:
クライアント側でのみ実行されるコードがサーバー側で実行されない場合、HTMLが一致しない可能性があります。この問題を解決するには、クライアント側で適切にレンダリングされるようにコードを修正するか、クライアントでのみ使用されるコードをサーバー側でも使用できるようにする必要があります。
動画での対策
動画ではクライアントサイドでだけレンダリングするラッパーコンポーネントを作成、
それをLayoutコンポーネント内で使用して対策している
参考
モーダルの状態管理にzustandを使用
A small, fast and scalable bearbones state-management solution using simplified flux principles. Has a comfy API based on hooks, isn't boilerplatey or opinionated.
小さくて、速くて、スケーラブルが売りらしい。Recoilと似ている??
Reduxだとデカすぎる時はいいかもしれない。
Reduxとの違い(by Chat GPT4)
Zustand と Redux は、React を使ったアプリケーションで状態管理を行うためのライブラリですが、それぞれ異なるアプローチを取っています。以下に、それぞれの特徴や違いを述べます。
簡潔さ:
Zustand は、シンプルで簡潔なAPIを提供しており、初心者にも扱いやすいです。一方、Redux はより複雑な概念と設定が必要です。アクション、アクションクリエイター、リデューサー、ミドルウェアなど、多くの要素を学ぶ必要があります。
アーキテクチャ:
Redux は、Flux アーキテクチャを採用しており、状態変更はアクションとリデューサーを通じて行われます。一方、Zustand はより直接的なアプローチを取り、状態オブジェクトを直接更新することができます。
ミドルウェア:
Redux では、ミドルウェアを利用して状態管理のロジックをカスタマイズすることができます。これにより、非同期処理やデバッグのためのツールなど、多くの拡張機能を導入することが可能です。Zustand はミドルウェアの概念がなく、代わりにカスタムフックを使ってロジックを組み込むことができます。
コミュニティとサポート:
Redux は、長い間Reactの状態管理のデファクトスタンダードとされており、豊富なドキュメントやサンプルが揃っています。また、多くの開発者が経験を持っているため、サポートも充実しています。Zustand は比較的新しいライブラリであり、コミュニティが小さく、ドキュメントやサポートも限定的です。
登録のモーダル内でreact-hook-formを使う
zod と組み合わせたりしてとても便利。
他のライブラリと親和性が高いのはいい。
react-hook-formを使うメリット(by Chat GPT4)
簡単な検証:
一般的なフォーム要素に対してバリデーションルールを簡単に適用できます。また、カスタム検証もサポートされています。
性能:
React Hook Formは、非制御コンポーネント(uncontrolled components)を使用するため、フォーム全体の再レンダリングを最小限に抑えることができます。これにより、パフォーマンスが向上します。
フックベースのAPI:
React Hook Formは、React Hooksを使ってAPIを提供しているため、クラスコンポーネントではなく関数コンポーネントでフォームの状態管理ができます。コードの簡潔さと再利用性が向上します。
エラーメッセージの管理:
エラーメッセージとバリデーションの結果を容易にアクセスできます。エラーメッセージは、自動的に生成され、適切なタイミングで更新されます。
フォームのリセット:
フォームのリセットが簡単に実行できます。ユーザーがフォームをクリアしたい場合や、送信後にフォームをリセットする必要がある場合に便利です。
TypeScriptサポート:
React Hook FormはTypeScriptをサポートしており、型安全を提供します。これにより、開発者はコードの品質と安定性を向上させることができます。
カスタムフック:
React Hook Formは、カスタムフックを作成する機能を提供しています。これにより、フォームロジックを共有したり、独自のバリデーションルールやカスタム機能を追加できます。
外部ライブラリとの統合:
React Hook Formは、多くのUIライブラリやデザインシステムと統合できます。これにより、開発者は既存のコンポーネントを容易に利用し、独自のスタイルや機能を追加できます。
フォームの状態管理:
React Hook Formは、フォームの状態(入力値、タッチ状態、検証状態、送信状態など)を効果的に管理できます。これにより、コンポーネント間で状態を共有したり、状態に応じてUIを最適化することが容易になります。
フォームのネスト:
フォーム内に複数のサブフォームをネストさせることができます。これにより、複雑なフォーム構造を持つアプリケーションでも、状態管理とバリデーションを効果的に行うことができます。
デフォルト値の設定:
React Hook Formを使用すると、簡単にフォーム要素のデフォルト値を設定できます。これにより、編集フォームのように、すでに値がある状態でフォームを表示する場合に便利です。
カスタムフォームフィールド:
React Hook Formでは、カスタムフォームフィールドを容易に作成できます。これにより、標準的なフォーム要素にない特殊な入力要件を満たすことができます。
フォームのテスト:
React Hook Formは、フォームの状態管理とバリデーションをテストしやすくするためのツールを提供しています。これにより、フォームの品質と安定性を向上させることができます。
ドキュメント:
React Hook Formのドキュメントは、詳細で親切であり、多くの例やデモが提供されています。これにより、開発者はライブラリの機能を短時間で習得し、問題を迅速に解決できます。
Prismaをインストール
MongoDB
データベースにはこちらのSaaSを使用。
無料枠でいける
Prismaを使うメリット(by Chat GPT4)
型安全:
Prismaは、TypeScriptと緊密に統合されており、コードに対して型安全を提供します。これにより、データベースの操作を行う際に間違った型や未定義のフィールドを使用することがなく、エラーの可能性を最小限に抑えることができます。
自動生成されるクライアントAPI:
Prismaは、データモデル定義に基づいてクライアントAPIを自動生成します。これにより、データベースの操作を簡単に行うことができ、開発者はデータモデルとAPIの整合性を手動で保つ手間を省くことができます。
易しさと生産性の向上:
Prismaは、データベース操作を簡単かつ直感的に行うためのAPIを提供します。これにより、開発者はデータベース操作を効率的に行い、生産性を向上させることができます。
データベース移行:
Prismaは、データモデル定義をデータベースのスキーマに自動的に反映させることができます。これにより、データベースの変更を簡単に追跡し、バージョン管理することができます。
柔軟性:
Prismaは、複数のデータベースエンジン(PostgreSQL、MySQL、SQLite、SQL Serverなど)と互換性があります。これにより、異なるデータベースを使用しているプロジェクトでも、Prismaを容易に導入できます。
パフォーマンスの最適化:
Prismaは、クエリの最適化やキャッシング機能を提供し、データベースのパフォーマンスを向上させます。
エコシステム:
Prismaは、GraphQLサーバー(Prisma Client)やデータベースマイグレーションツール(Prisma Migrate)など、関連ツールやライブラリとの統合が容易です。これにより、開発者はPrismaを使用したアプリケーシション開発において、一貫性のあるエコシステムを構築し、効率的に作業することができます。
コミュニティとサポート:
Prismaは、活発なコミュニティと充実したドキュメントを持っています。開発者は、問題の解決や最新の開発手法を学ぶために、これらのリソースを利用することができます。
データベース操作の抽象化:
Prismaは、データベース操作を抽象化し、開発者がSQLクエリを直接書く必要がなくなります。これにより、開発者はデータベース操作をよりシンプルに行い、コードの可読性と保守性を向上させることができます。
プラグインアーキテクチャ:
Prismaはプラグインアーキテクチャを採用しており、コミュニティによって開発されたプラグインを利用することで、追加機能やカスタマイズが容易に行えます。
準備
Prismaは事前にある程度、キャッチアップした方がいいです。
以下辺りで勉強すると良いかなと。
prisma.schemaを編集
直感的でとてもわかりやすい。relationさせたり。
これでDB側のテーブルまで作れるの凄い。
ユーザーが複数の認証プロバイダーでサインインできるようにするために、Userモデルとは別のモデルとしてAccountモデルがを作成しているらしい、なるほど、、!
npx prisma db push
で、mongoDB側にtableが作成されている、、!
next-auth
npm install next-auth @next-auth/prisma-adapter
next-authとprismaを紐づけるprisma-adapterもインストール
PrismaClientを作成する
動画では、nextjsのホットリロード機能で、Prisma Clientが何度も生成されないようにしている。
なるほど。。
通常のログイン認証、githubログイン、googleログインを実装
こんなに簡単に出来る。
パスワードをそのままDBに保存するのはまずいのでbcryptでハッシュ化する
DBに登録する前にhash化する、
パスワードが入力された時の比較にも使用する
compareとhash
https://youtu.be/c_-b_isI4vg?t=7307
https://youtu.be/c_-b_isI4vg?t=7642
ハイドレーションエラー再び
https://youtu.be/c_-b_isI4vg?t=8917
`getServerSession` is used in a React Server Component.
https://next-auth.js.org/configuration/nextjs#getServerSession}
https://next-auth.js.org/warnings#EXPERIMENTAL_API
[next-auth][warn][NEXTAUTH_URL]
https://next-auth.js.org/warnings#nextauth_url
[next-auth][warn][DEBUG_ENABLED]
https://next-auth.js.org/warnings#debug_enabled
Warning: Only plain objects can be passed to Client Components from Server Components. Date objects are not supported.
{id: ..., name: "gosan", email: ..., emailVerified: ..., image: ..., hashedPassword: ..., createdAt: Date, updatedAt: ..., favoritedIds: ...}
React Server ComponentsからClient Componentsに渡されるオブジェクトがプレーンオブジェクトである必要があることを示しています。Dateオブジェクトはサポートされていません。プレーンオブジェクトとは、基本的にプロパティとその値から構成されるシンプルなJavaScriptオブジェクトです。Dateオブジェクトや他の複雑なオブジェクトは、クライアントコンポーネントに直接渡すことはできません。
createdAtなどがDate型であるため、Client Componentに渡す前に、string型に変換する必要がある。
typeを1回、Omitして消した後に、再度定義して押して結合している。
これは賢い。
enum
https://youtu.be/c_-b_isI4vg?t=12137
enum出てきた。
以前から存在意義がよくわからなかった。
enum STEPS {
CATEGORY = 0,
LOCATION = 1,
INFO = 2,
IMAGES = 3,
DESCRIPTION = 4,
PRICE = 5,
}
なるほどねー。
普通にオブジェクトリテラルでこういうことをやっていたけど、
あえて、enumを使う必要があるのかな?
原因とその対策(by Chat GPT4)
このように、「enum」を使用することで、名前付きの定数を使ってワークフローのステップを表現することができます。これにより、コードの読みやすさと可読性が向上します。また、数値ではなく名前付きの定数を使ってワークフローのステップを表現することで、コードに意味を与えることができます。
参考
useForm の 機能
https://www.youtube.com/watch?v=c_-b_isI4vg&t=11503s
watch
値の監視が出来る
const category = watch('category')
setValue
登録済みフィールドの値を動的に設定し、フォームの状態を検証および更新するオプションを使用できます。不要な再レンダリングを回避する
第一引数:name
第二引数:value
第三引数:options
setValue(id, value, {
shouldValidate:true, // バリデートに加えるか
shouldDirty: true, // 変更されたかの判定をするか
shouldTouch:true, // inputにタッチされた状態にするか
})
プログラミングの文脈では、"dirty" は「変更された」や「編集された」といった意味を持ちます。特にフォームや入力フィールドが変更された場合に、データが "dirty" になると言われます。
dirtyは編集されたって意味になるのね。
参考