Closed yanachuwan9sm closed 8 months ago
公式が推しているのはやっぱり Tailwind CSS。 以下の連載にある内容をある程度理解すれば、Tailwind に関しては問題ないと思う。
慣れるまでは以下のチートシートも便利。 https://nerdcave.com/tailwind-cheat-sheet
Tailwind CSS に関するプラグインやIDE拡張などは以下のレポジトリにまとめられているので迷った場合は参考にするとよい。https://github.com/aniftyco/awesome-tailwindcss
画像の最適化は、ウェブ開発における大きなトピックであり、それ自体がひとつの専門分野とも言えます。
主に考えられる画像の最適化は以下の4つ。手動で実現するにはどの様なアプローチがあるかは、知っておくと良い。next/image
なら全部やっちゃうぜ!て話ではあるけども。(苦手、、苦手、、)
🌟 上記の4項目を next/image
ではどうやって実現しているんだい?は別トピックで調べても良いな。
🌟 Vercelチームがレコメンドしている以下の記事を読んで、TILかコンテンツにまとめるのも別トピックでやる。
データ取得にServer Componentsを使用する デフォルトでは、Next.jsアプリケーションはReact Server Componentsを使用し、必要に応じてClient Componentsを選択できます。React Server Componentsでデータを取得すると、いくつかの利点があります:
Server Componentsはサーバー上で実行されるため、高価なデータ取得とロジックをサーバー上に保持し、結果のみをクライアントに送信できます。 Server Componentsはpromiseをサポートしており、データ取得のような非同期タスクのためのシンプルなソリューションを提供します。useEffectやuseState、データ取得ライブラリに手を伸ばすことなく、async/await構文を使用できます。 サーバーコンポーネントはサーバー上で実行されるため、APIレイヤーを追加することなくデータベースに直接問い合わせ> ることができます。
シンプルかつ分かりやすいサーバーコンポーネントの説明だね。
App Router以前 : アプリケーション(ページ)単位でSSG、ISR、SSRとかしてた。 App Routerから : cacheをどう扱うかで、コンポーネント単位でstatic/dynamic renderingを行う。
App Router は、pages のページ単位のリクエストとはモデルが違うので、様々なアプローチを持つ cache を理解することが App Router を理解することに繋がる気がする。
cacheを理解する理由として、CDNサーバーを自分で用意する場合は、可能な限り Next.js サーバー側にキャッシュを握られないように(オリジンとの多段キャッシュを防止)する必要がある事も考えれる。
(疑問) fetch単位のキャッシュに対して、レスポンスヘッダを切り替える事はできるのか?(Pages の getServerSideProps なら可能だった)
https://nextjs.org/docs/app/building-your-application/caching
Reactのさまざまなデータフェッチ方法を比較して理解して正しく使用する - SSR + App Router Cache編
// 個々の `fetch` リクエストに対してキャッシュされない様にする。
fetch(`https://...`, { cache: 'no-store' })
// 上記と同義
import { unstable_noStore as noStore } .from 'next/cache';
export async function fetchRevenue() {
noStore();
fetch(`https://...`);
}
// Route Segment Config オプションでルートセグメント全体がキャッシュされない様にする。(3rd Party含)
export const dynamic = 'force-dynamic'
You can use a Next.js API called unstable_noStore inside your Server Components or data fetching functions to opt out of static rendering. サーバーコンポーネントやデータ取得関数の内部でunstable_noStoreと呼ばれるNext.js APIを使用すると、静的レンダリングを省略できます。これを追加してみましょう。
unstable_noStore
と cache: ‘no-store’
どっちがええんや?
ストリーミング 👉 ルートを小さな “チャンク “に分割し、準備ができ次第、サーバーからクライアントに順次ストリーミングするデータ転送技術である。
ページレベル : loading.tsx
ファイル
特定のコンポーネントレベル : <Suspense>
を使用
React Suspenseでは、何らかの条件が満たされるまで(例えばデータが読み込まれるまで)、アプリケーションの一部のレンダリングを延期することができます。動的コンポーネントをSusppenseでラップすることができます。そして、動的コンポーネントのロード中に表示するフォールバックコンポーネントを渡します。
Great! You’re almost there, now you need to wrap the
components in Suspense. You can fetch data for each individual card, but this could lead to a popping effect as the cards load in, this can be visually jarring for the user.
popping effect という表現。(初めて聞いた)
サスペンスの境界線をどこに置くかを決める サスペンスの境界線をどこに置くかは、いくつかの事柄によって決まります: ユーザーにどのようにページを体験してもらいたいか。 どのコンテンツを優先するか。 コンポーネントがデータ取得に依存している場合。 ダッシュボードのページを見てみてください。 心配しないでください。正解はありません。 Susppenseは、より楽しいユーザー体験を生み出すための強力なAPIです。
チュートリアルとしては実践的な章かも。 state管理とURL管理があり、URL管理行っている。
利点を以下のように簡潔に説明ができるとカッケェす、、!
ブックマークおよび共有可能なURL:検索パラメータはURL内にあるため、ユーザーは検索クエリやフィルタを含むアプリケーションの現在の状態をブックマークし、将来の参照や共有に利用できる。
サーバーサイド・レンダリングと初期ロード:初期状態をレンダリングするために、URLパラメータをサーバー上で直接消費することができ、サーバーレンダリングの処理が容易になります。
アナリティクスとトラッキング:検索クエリやフィルタをURLに直接記述することで、クライアントサイドのロジックを追加することなく、ユーザーの行動をトラッキングしやすくなります。
制御コンポーネントと非制御コンポーネントについても触れてる。
(入力の値を管理するために状態を使用する) value属性を使用して制御されたコンポーネントにする -> Reactが入力の状態を管理することを意味する。
(入力の値を管理するために状態を使用しない) defaultValueを使用する。-> ネイティブ入力が自身の状態を管理することを意味する
どちらを使うかは、クライアントで作業しているかサーバで作業しているかによる。(一般的なルールとして、クライアントからパラメータを読み込みたい場合、useSearchParams()
hook を使用する)
Client Component 👉 クライアントからパラメータにアクセスするためにuseSearchParams()
hook を使用。
Server Component 👉 ページからコンポーネントにsearchParamsをpropsとして渡すことができます。
export default async function Page({
searchParams,
}: {
searchParams?: {
query?: string;
page?: string;
};
}) {
const query = searchParams?.query || '';
const currentPage = Number(searchParams?.page) || 1;
return (
//......
<Suspense key={query + currentPage} fallback={<InvoicesTableSkeleton />}>
<Table query={query} currentPage={currentPage} />
</Suspense>
//.....
);
}
https://nextjs.org/docs/app/api-reference/file-conventions/page
Debouncing の仕組みの説明シンプルでいいな〜
How Debouncing Works: Trigger Event: When an event that should be debounced (like a keystroke in the search box) occurs, a timer starts. Wait: If a new event occurs before the timer expires, the timer is reset. Execution: If the timer reaches the end of its countdown, the debounced function is executed.
デバウンスの仕組み トリガーイベント: デバウンスすべきイベント(検索ボックスのキー入力など)が発生すると、タイマーがスタートする。 待機:タイマーが切れる前に新しいイベントが発生すると、タイマーがリセットされます。 実行: タイマーのカウントダウンが終了すると、デバウンス機能が実行される。
非同期コードをサーバー上で直接実行できます。これにより、データを変更するためのAPIエンドポイントを作成する必要がなくなります。
その代わりに、サーバー上で実行される非同期関数を記述し、クライアントまたはサーバーコンポーネントから呼び出すことができます。
Webアプリケーションは様々な脅威にさらされやすいため、セキュリティは最優先事項です。そこでサーバーアクションの出番です。効果的なセキュリティソリューションを提供し、さまざまなタイプの攻撃から保護し、データを保護し、認証されたアクセスを保証します。Server Actionsは、POSTリクエスト、暗号化されたクロージャ、厳密な入力チェック、エラーメッセージのハッシュ化、ホストの制限などの技術によってこれを実現し、これらすべてが連携してアプリの安全性を大幅に高めます
え、Vercelはセキュリティの観点から Server Action をおしてたの?
サーバー上で実行される非同期関数をコンポーネントからAPIなしで呼び出せるぜ!ネイティブの HTML の要素のみで完結するよ!を推してるのかと思った。
サーバー コンポーネント内でサーバー アクションを呼び出す利点は、プログレッシブ拡張機能です。
一応、プログレッシブエンハンスメントなフォームの実現はメリットにあげてくれた。
サーバーアクションは、Next.jsのキャッシュ にも深く統合されています。サーバーアクションでフォームが送信されると、アクションを使用してデータを変更できるだけでなく、
revalidatePath
やrevalidateTag
などの API を使用して、関連するキャッシュを再検証することもできます。
特にコメントないけど、メモ。
HTMLでは、action属性にURLを渡します。このURLはフォームデータの送信先(通常はAPIエンドポイント)になります。
しかしReactでは、action属性は特別なpropとみなされる。つまりReactは、アクションが呼び出されるようにその上に構築する。
その裏で、Server Actions はPOSTAPI エンドポイントを作成します。このため、Server Actionsを使用する際には、APIエンドポイントを手動で作成する必要はありません。
HTML と React における action
属性の仕様の違いもしっかり説明されていて良い。やっぱり裏側では POST APIエンドポイントを作ってるのか。
多分その中で、暗号化されたクロージャ、厳密な入力チェック、エラーメッセージのハッシュ化、ホストの制限とかもやってるからセキュリティ面でも良い選択ってこと?
多数のフィールドを持つフォームを扱う場合は、JavaScript のObject.fromEntries() と共にentries()メソッドを使用することをお勧めします。
const rawFormData = Object.fromEntries(formData.entries())
Next.jsには、ルートセグメントをユーザーのブラウザに一時的に保存するクライアントサイドルーターキャッシュがあります。プリフェッチとともに、このキャッシュは、サーバーへのリクエスト数を減らしながら、ユーザーがルート間をすばやく移動できるようにします。
Router Cacheの説明が Server Actions の再検証・リダレクトのタイミングで来た。コイツのせいで、App Routerにおける cache がかなりややこい事になってるんだよな。
Router Cache(クライアント)のキャッシュをクリアして、サーバーへの新しいリクエストをトリガーするには revalidatePath関数を使うという事。
Server Actionsに、引数を渡すにはbind
を利用する。
const updateInvoiceWithId = updateInvoice.bind(null, invoice.id);
return (
<form action={updateInvoiceWithId}>。
<input type="hidden" name="id" value={invoice.id}。/>
</form>
);
ページレベル(ルートセグメント)でerrorを制御 -> error.tsx
404エラー(リソースが存在しない)の場合は、notFound
関数を使う。
'use client';
import { useEffect } from 'react';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// Optionally log the error to an error reporting service
console.error(error);
}, [error]);
return (
<main className="flex h-full flex-col items-center justify-center">
<h2 className="text-center">Something went wrong!</h2>
<button
className="mt-4 rounded-md bg-blue-500 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-400"
onClick={
// Attempt to recover by trying to re-render the invoices route
() => reset()
}
>
Try again
</button>
</main>
);
}
error.tsxはClient Componentである必要がある。("use client")
また、2つのpropsを受け入れる。 error:このオブジェクトは、JavaScriptのネイティブErrorオブジェクトのインスタンスです。 reset:これは、エラー境界をリセットするための関数です。実行されると、この関数はルートセグメントの再レンダリングを試みます。
notFoundはerror.tsxよりも優先されるので、より具体的なエラーに対処したい場合は、notFoundを使うことができる!
Error Handling error.js API Reference notFound() API Reference not-found.js API Reference
eslint-plugin-jsx-a11y
クライアントでの検証 -> フォームの要素や
サーバーサイドでの検証 -> useFormState
hook と zod の safeParse
でやる。
ウェブ開発では、認証と認可は異なる役割を果たす:
認証とは、ユーザーが本人であることを確認することです。ユーザー名とパスワードのようなもので、本人であることを証明するのです。 認可は次のステップである。ユーザーの身元が確認されると、認可はアプリケーションのどの部分の使用を許可するかを決定する。 つまり、認証はあなたが誰であるかをチェックし、認可はあなたがアプリケーションで何ができるか、何にアクセスできるかを決定する。
認証と認可の違いから説明されてる。
メタデータはウェブページのSEOを強化する上で重要な役割を果たし、検索エンジンやソーシャルメディアプラットフォームにとってよりアクセスしやすく、理解しやすいものにします。適切なメタデータは、検索エンジンがウェブページを効果的にインデックスし、検索結果でのランキングを向上させるのに役立ちます。さらに、Open Graphのようなメタデータは、ソーシャルメディア上で共有されたリンクの見栄えを改善し、コンテンツをユーザーにとってより魅力的で有益なものにします。
知っておいて損はありません: ImageResponseコンストラクタを使用して、動的な OG 画像を作成することもできます。
satoriについてもNotesの中で言及されてる。
import { Metadata } from 'next';
export const metadata: Metadata = {
title: {
template: '%s | Acme Dashboard',
default: 'Acme Dashboard',
},
description: 'The official Next.js Learn Dashboard built with App Router.',
metadataBase: new URL('https://next-learn-dashboard.vercel.sh'),
};
テンプレート内の%sは特定のページタイトルに置き換えられるの知らなかった。
全体的に Vercel の書くドキュメントで使用するライブラリは結構厳選されてて、「それってコピペでも対応できるよね?普通に処理できるよね?」ってやつは、少し冗長ながらも実装してる感じがある。(外部依存を極力なくそうとする姿勢)
Vercelとしては、フラグを用いたコンポーネントの出し分けは、三項演算子使うんだ〜と思った。
isFlag && <Hoge/> // falsy か それ以外か
isFlag ? <Hoge/> : null // undefined or null か それ以外か
前者(&&
)の場合は、以下のJSXとJavaScriptにおける仕様の違いに注意が必要。
(JavaScript)条件をテストする際、左の辺を自動的に真偽値に変換する (JSX)左の辺が 0 の場合は、式全体がその 0 という値に評価される
:右向き指差し: React は何もレンダーしないのではなく 0 を表示してしまう。(二重否定でこの落とし穴は回避できるけど、普通の否定と組み合わせると紛らわしいんだよな。)
https://ja.react.dev/learn/conditional-rendering#logical-and-operator-
Sprint Goal
Learn Next.jsを読む。
ソースコードも公開しているので、気づき・参考になる部分があれば記載する。
🎌 period
Best Resource
Next.jsドキュメント
Next.jsリポジトリ
Next.js テンプレート
ヴェルセルYouTube