yanachuwan9sm / til

Today's I Learned for me.
0 stars 0 forks source link

Learn Next.js を読む #9

Closed yanachuwan9sm closed 8 months ago

yanachuwan9sm commented 9 months ago

Sprint Goal

🎌 period

Best Resource

Next.jsドキュメント

Next.jsリポジトリ

Next.js テンプレート

ヴェルセルYouTube

yanachuwan9sm commented 9 months ago

CSS Styling

公式が推しているのはやっぱり Tailwind CSS。 以下の連載にある内容をある程度理解すれば、Tailwind に関しては問題ないと思う。

https://gihyo.jp/list/group/Tailwind-CSS%E5%AE%9F%E8%B7%B5%E5%85%A5%E9%96%80-%EF%BD%9E%E3%81%BE%E3%81%9A%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%8B%E3%82%89-%E3%81%82%E3%81%A8%E3%81%A7%E5%85%B1%E9%80%9A%E5%8C%96%E3%81%99%E3%82%8B#rt:/article/2023/07/tailwindcss-practice-02

慣れるまでは以下のチートシートも便利。 https://nerdcave.com/tailwind-cheat-sheet

Tailwind CSS に関するプラグインやIDE拡張などは以下のレポジトリにまとめられているので迷った場合は参考にするとよい。https://github.com/aniftyco/awesome-tailwindcss

yanachuwan9sm commented 9 months ago

Optimizing Fonts and Images

画像の最適化は、ウェブ開発における大きなトピックであり、それ自体がひとつの専門分野とも言えます。

主に考えられる画像の最適化は以下の4つ。手動で実現するにはどの様なアプローチがあるかは、知っておくと良い。next/image なら全部やっちゃうぜ!て話ではあるけども。(苦手、、苦手、、)

🌟 上記の4項目を next/image ではどうやって実現しているんだい?は別トピックで調べても良いな。

🌟 Vercelチームがレコメンドしている以下の記事を読んで、TILかコンテンツにまとめるのも別トピックでやる。

yanachuwan9sm commented 9 months ago

Fetching Data

データ取得にServer Componentsを使用する デフォルトでは、Next.jsアプリケーションはReact Server Componentsを使用し、必要に応じてClient Componentsを選択できます。React Server Componentsでデータを取得すると、いくつかの利点があります:

Server Componentsはサーバー上で実行されるため、高価なデータ取得とロジックをサーバー上に保持し、結果のみをクライアントに送信できます。 Server Componentsはpromiseをサポートしており、データ取得のような非同期タスクのためのシンプルなソリューションを提供します。useEffectやuseState、データ取得ライブラリに手を伸ばすことなく、async/await構文を使用できます。 サーバーコンポーネントはサーバー上で実行されるため、APIレイヤーを追加することなくデータベースに直接問い合わせ> ることができます。

シンプルかつ分かりやすいサーバーコンポーネントの説明だね。

yanachuwan9sm commented 9 months ago

Static and Dynamic Rendering

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_noStorecache: ‘no-store’どっちがええんや?

yanachuwan9sm commented 9 months ago

Streaming

ストリーミング 👉 ルートを小さな “チャンク “に分割し、準備ができ次第、サーバーからクライアントに順次ストリーミングするデータ転送技術である。

Next.jsでストリーミングを実装する方法

ページレベル : 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です。

yanachuwan9sm commented 9 months ago

Adding Search and Pagination

チュートリアルとしては実践的な章かも。 state管理とURL管理があり、URL管理行っている。

なんでURL検索パラメータで管理するのか?

利点を以下のように簡潔に説明ができるとカッケェす、、!

ブックマークおよび共有可能なURL:検索パラメータはURL内にあるため、ユーザーは検索クエリやフィルタを含むアプリケーションの現在の状態をブックマークし、将来の参照や共有に利用できる。

サーバーサイド・レンダリングと初期ロード:初期状態をレンダリングするために、URLパラメータをサーバー上で直接消費することができ、サーバーレンダリングの処理が容易になります。

アナリティクスとトラッキング:検索クエリやフィルタをURLに直接記述することで、クライアントサイドのロジックを追加することなく、ユーザーの行動をトラッキングしやすくなります。

input elements : defaultValue vs. value / Controlled vs. Uncontrolled

制御コンポーネントと非制御コンポーネントについても触れてる。

(入力の値を管理するために状態を使用する) value属性を使用して制御されたコンポーネントにする -> Reactが入力の状態を管理することを意味する。

(入力の値を管理するために状態を使用しない) defaultValueを使用する。-> ネイティブ入力が自身の状態を管理することを意味する

When to use the useSearchParams() hook vs. the searchParams prop?

どちらを使うかは、クライアントで作業しているかサーバで作業しているかによる。(一般的なルールとして、クライアントからパラメータを読み込みたい場合、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

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.

デバウンスの仕組み トリガーイベント: デバウンスすべきイベント(検索ボックスのキー入力など)が発生すると、タイマーがスタートする。 待機:タイマーが切れる前に新しいイベントが発生すると、タイマーがリセットされます。 実行: タイマーのカウントダウンが終了すると、デバウンス機能が実行される。

yanachuwan9sm commented 9 months ago

Mutating Data

Server Actions

非同期コードをサーバー上で直接実行できます。これにより、データを変更するためのAPIエンドポイントを作成する必要がなくなります

その代わりに、サーバー上で実行される非同期関数を記述し、クライアントまたはサーバーコンポーネントから呼び出すことができます。

Webアプリケーションは様々な脅威にさらされやすいため、セキュリティは最優先事項です。そこでサーバーアクションの出番です。効果的なセキュリティソリューションを提供し、さまざまなタイプの攻撃から保護し、データを保護し、認証されたアクセスを保証します。Server Actionsは、POSTリクエスト、暗号化されたクロージャ、厳密な入力チェック、エラーメッセージのハッシュ化、ホストの制限などの技術によってこれを実現し、これらすべてが連携してアプリの安全性を大幅に高めます

え、Vercelはセキュリティの観点から Server Action をおしてたの?

サーバー上で実行される非同期関数をコンポーネントからAPIなしで呼び出せるぜ!ネイティブの HTML の要素のみで完結するよ!を推してるのかと思った。

サーバー コンポーネント内でサーバー アクションを呼び出す利点は、プログレッシブ拡張機能です。

一応、プログレッシブエンハンスメントなフォームの実現はメリットにあげてくれた。

yanachuwan9sm commented 9 months ago

Mutating Data

サーバーアクションは、Next.jsのキャッシュ にも深く統合されています。サーバーアクションでフォームが送信されると、アクションを使用してデータを変更できるだけでなく、revalidatePathrevalidateTag などの 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 がかなりややこい事になってるんだよな。

https://github.com/AkifumiSato/nextjs-router-cache-slide/blob/700ebc2c3cf719e2ddee2ce6755b4160394734ca/slides.md

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>
 );
yanachuwan9sm commented 9 months ago

Handling Errors

ページレベル(ルートセグメント)でerrorを制御 -> error.tsx

404エラー(リソースが存在しない)の場合は、notFound関数を使う。

error.tsx

'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

yanachuwan9sm commented 9 months ago

Improving Accessibility

eslint-plugin-jsx-a11y

フォームバリデーション

クライアントでの検証 -> フォームの要素や