Closed99

新しいLearn Next.jsを読んでみる

ピン留めされたアイテム
hajimismhajimism

ざっと読んだ感想

App Routerの機能に限らず周辺領域にたくさん言及されていて、「こういうメンタルモデルでやっていこうぜ!」っていうのがわかりやすい資料だった。種々の説明は端的でわかりやすく、ハンズオンの内容もとても実践的なので読み応えがある。

experimentalな機能についてもいくつか盛り込まれており、そこは賛否両論ありそう?KentがNextを使いたくない理由の一つに「アプデが忙しなすぎ」っていうのを挙げていたけど、そういう側面が如実に現れているのかなーという気がした。たぶん「今はたまたまexperimentalだけど、おれたちの目指す世界観からしたらこれは概ね必須のAPIだから!」って気持ちで盛り込まれていると思う。

hajimismhajimism

一旦クローズしちゃいますけど皆様のコメントWelcomeです。

hajimismhajimism

各章で目についたところだけ拾ってこうかな
https://nextjs.org/learn/dashboard-app/getting-started

hajimismhajimism

おお?Private foldersが使われてないな。あとでそうするってことかな。

hajimismhajimism

ぼくがモックデータと呼んでいるもの、ここではplaceholder-dataと呼ぶらしい。へ〜。

hajimismhajimism

なんかいやに実践的だな。モデルの型定義がしっかりあるぞ。

export type Invoice = {
  id: string;
  customer_id: string;
  amount: number;
  date: string;
  // In TypeScript, this is called a string union type.
  // It means that the "status" property can only be one of the two strings: 'pending' or 'paid'.
  status: 'pending' | 'paid';
};
hajimismhajimism

We're manually declaring the data types, but for better type-safety, we recommend tools like Prisma, which automatically generates types based on your database schema.

Prismaが公式でおすすめされているなあ

hajimismhajimism

お、進捗インジケータは前から引き継がれてる。前はポイント貯まる形式だったっけ?

hajimismhajimism
hajimismhajimism

プロジェクトは予めスタイリングがつけられておらず、そこからはじめるらしい。何順なんだろうこれ。わかりやすい順?最初は変化が大きいやつで楽しませる設計?

hajimismhajimism

typeじゃね? border-r-[20px]の最後の]が抜けてる気がする。

  className="h-0 w-0 border-b-[30px] border-l-[20px] border-r-[20px border-b-black border-l-transparent border-r-transparent"
hajimismhajimism

CSS Moduleも紹介されているけど、Tailwindが先なんやなあ

hajimismhajimism

clsxも紹介されてんなあ。前もこんな個別のライブラリにフォーカス当ててる感じだったっけ?

hajimismhajimism

Take a look at the CSS documentation for more information.

うまいことドキュメントへの誘導があっていいねー

hajimismhajimism
hajimismhajimism

え、答えを隠す系のUI、トグルっぽいものを使わずにボタンだけでやってるなあ

hajimismhajimism

next/imageの解説は全俺が期待していたのでありがとうございます。

デバイスごとの画像の切り替えこれでいいのかあと安心する。

  <div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12">
      {/* Add Hero Images Here */}
      <Image
        src="/hero-desktop.png"
        width={1000}
        height={760}
        className="hidden md:block"
        alt="Screenshots of the dashboard project showing desktop and mobile versions"
      />
      <Image
        src="/hero-mobile.png"
        width={560}
        height={620}
        className="block md:hidden"
        alt="Screenshot of the dashboard project showing mobile version"
      />
    </div>

そしてこれでいい理由もちゃんと書いてある。

Resizing images to avoid shipping large images to devices with a smaller viewport.

hajimismhajimism

個人的に、別スクラップでrefふくめ集中して読みたい章かも

hajimismhajimism
hajimismhajimism

By having a special name for page files, Next.js allows you to colocate UI components, test files and other related code with your routes. Only the content inside the page file will be publicly accessible.

colocateについてちゃんと言及されているな

hajimismhajimism

ダッシュボードレイアウトが説明しやすいよねーやっぱ

hajimismhajimism
hajimismhajimism

Why optimize navigation?
To link between pages, you'd traditionally use the <a> HTML element. At the moment, the sidebar links use <a> elements, but notice what happens when you navigate between the home, invoices, and customers pages on your browser.

Did you see it?

There's a full page refresh on each page navigation!

画像のとこでも思ったけど、「最適化しないとどうなるか?」を端的に書いてくれているのが教えるの上手い人って感じする。

hajimismhajimism

おお?ぬるっとクライアントコンポーネントという概念が出てきた。もう前提知識として扱うんだなこれ。

Since usePathName() is a hook, you'll need to turn nav-links.tsx into a Client Component. Add React's “use client” directive to the top of the file, then import usePathName() from next/navigation:

hajimismhajimism

App Routerコワイになってるひと、大体RSC/RCCコワイで止まっている気がしたので、気になった

hajimismhajimism

In addition to client-side navigation, Next.js automatically code splits your application by route segments. This is different from a traditional SPA, where browser loads all your application code on initial load.

Splitting code by routes means that pages become isolated. If a certain page throws an error, the rest of the application will still work.

ここも端的にメリットを説明しててうまいなあ

hajimismhajimism
hajimismhajimism

If you are using React Server Components (fetching data on the server), you can skip the API layer, and query your database directly without risking exposing your database secrets to the client.

ここが伝わるようにってことかなあ

hajimismhajimism

Using Server Components to fetch data
By default, Next.js applications use React Server Components, and you can opt into Client Components when needed. There are a few benefits to fetching data with React Server Components:

  • Server Components execute on the server, so you can keep expensive data fetches and logic on the server and only send the result to the client.
  • Server Components support promises, providing a simpler solution for asynchronous tasks like data fetching. You can use async/await syntax without reaching out for useEffect, useState or data fetching libraries.
  • Since Server Components execute on the server, you can query the database directly without an additional API layer.

まあでも最重要だからなあこれ。DB用意するのは教育的には妥当かあ。

hajimismhajimism

Using SQL

えー、なんかやっぱりNext.jsを学ぶ資料の真ん中にVercel Postgresの説明が入ってくるのはうーんて感じするけどな

hajimismhajimism

しかもfetch関数の中身は最初からlibに書いてあるんかいっ

hajimismhajimism

But with SQL, you can fetch only the data you need. It's a little longer than using Array.length, but it means less data needs to be transferred during the request. This is the SQL alternative:

めっちゃSQLの説明してくるなあー。フルスタックフレームワークであることを全面に出してきているってことかなあ。

hajimismhajimism

What are request waterfalls?

waterfallsの説明あるの純粋にいいね

hajimismhajimism

え、Promise.allで終わり!?Suspenseは??ページでデータフェッチすんなって言ってくれよ

hajimismhajimism
hajimismhajimism

You can use a Next.js API called unstable_noStore inside your Server Components or data fetching functions to opt-out of static rendering. Let's add this.

シンプルにunstable_noStore知らんかった。説明はわかりやすかったけど learnにexperimental APIを使わざるを得ないところが、この資料の問題と言うよりNext.jsの課題に感じた。あえてなのかな。

hajimismhajimism

お、お、お!ここでSuspenseかあ。よかったあ。さっきはごめんなさい。
https://nextjs.org/learn/dashboard-app/streaming

hajimismhajimism

(誰かにおすすめするときは、少なくとも7,8,9はセットで読んでもらう必要がある)

hajimismhajimism

By streaming, you can prevent slow data requests from blocking your whole page. This allows the user to see and interact with parts of the page without waiting for all the data to load before any UI can be shown to the user.

With streaming, data fetching and rendering for each chunk is also initiated in parallel, solving the waterfall problem.

説明はほんとに端的で上手なんだよなあ

hajimismhajimism

クイズなあ、説明の直後についているから絶対答え覚えてるんだよなあ。章末にまとめてあってもいいと思った。

hajimismhajimism

There are two ways you implement streaming in Next.js:

  • At the page level, with the loading.tsx file.
  • For specific components, with <Suspense>.
    Let's see how this works.

loading.tsxがSuspenseとセットで説明されているのはありがたいと思った。いやまあ普通にやればそうなるんだけど、「特別なファイル集」として説明されると抵抗感出ると思うので。

hajimismhajimism

Luckily, we can fix this with Route Groups. Create a new folder called /(overview) inside dashboard folder. Then, move your loading.tsx and page.tsx files inside the folder:

おー、Route Groupsの説明ここで差し込んでくるのか。上手い気がした。

hajimismhajimism

Suspenseを用いたRevenueChartのrefactor(もはやfixか?)。とてもいい説明。

このノリでContainer/Presenterへの言及ないかな。

hajimismhajimism

Deciding where to place your Suspense boundaries

良い説明だなーと思いつつ、これはReact fundamentalの範疇だと思うので、Next.jsだけを説明してやろう!っていう意図で作られた資料じゃないんだなこれは。

hajimismhajimism

ふつうに気になる章に入った
https://nextjs.org/learn/dashboard-app/partial-prerendering

hajimismhajimism

デフォルトで隠されているコンテンツをここに引用してくるのは申し訳ないと思いつつ、これはめちゃくちゃいい図だと思った

前までアプリケーション単位でSSGとかSSRとか言ってたけど、cacheという切り口で考えることでコンポーネント単位でstatic/dynamicが変わってくるよー、ってのがStreamingからの流れでよく伝わるきがする。

hajimismhajimism

In Next.js 14, you can use a new rendering model called Partial Prerendering (PPR). PPR is an experimental feature that allows you to render a route statically, while keeping some parts dynamic. In other words, you can isolate the dynamic parts of a route. For example:

PPRだって。また3文字略語だね。

hajimismhajimism

It's worth noting that wrapping a component in Suspense doesn't make the component itself dynamic (remember you used unstable_noStore to achieve this behavior), but rather Suspense is used as a boundary between the static and dynamic parts of your route.

The great thing about PPR is that you don't need to change your code to use it. As long as you're using Suspense to wrap the dynamic parts of your route, Next.js will know which parts of your route are static and which are dynamic.

自然なインターフェイスやなーとも思えるし、いや裏でゴニョゴニョしすぎでしょとも思えるな

hajimismhajimism

まあでも教育にいいのは間違いなくて、data fetchingの章からここまでセットで読むとメンタルモデルが醸成されそう

hajimismhajimism
hajimismhajimism

Why use URL search params?

おーこういうところにも言及されてるの素晴らしいな。めちゃ分厚くない??

hajimismhajimism

おーなんか、URLをひとつのstateとして見ようねーみたいな意図が感じられる気がするな

  function handleSearch(term: string) {
    const params = new URLSearchParams(searchParams);
    if (term) {
      params.set('query', term);
    } else {
      params.delete('query');
    }
    replace(`${pathname}?${params.toString()}`);
  }
}
hajimismhajimism

defaultValue vs. value / Controlled vs. Uncontrolled

こんなところまで触れられてるんだ、いいね。state管理とURL管理の違いもよく伝わるし。

しょうもないけど"defaultValue vs. value"という並びなら" Uncontrolled vs. Controlled"のほうがいいのでは、と思った(というかvalue vs defaultValueとするのが良さそう)

hajimismhajimism

ここではuse-debounceが紹介されてる。個別のライブラリの紹介を惜しまないなあ。

hajimismhajimism

These patterns are different to what you may be used to when working on the client only, but hopefully, you have some skills to implement functionality that spans both the server and the client!

やはりサーバーとクライアントにまたがるシーンを意図して盛り込んでいるっぽい

hajimismhajimism
hajimismhajimism

What are Server Actions?

React Server Actions allow you to run asynchronous code directly on the server. They eliminate the need to create API endpoints to mutate your data. Instead, you write asynchronous functions that execute on the server and can be invoked from your Client or Server Components.

Security is a top priority for web applications, as they can be vulnerable to various threats. This is where Server Actions come in. They offer an effective security solution, protecting against different types of attacks, securing your data, and ensuring authorized access. Server Actions achieve this through techniques like POST requests, encrypted closures, strict input checks, error message hashing, and host restrictions, all working together to significantly enhance your app's safety.

stableになりましたから当然入ってきますよねえ。セキュリティ面からの説明なんだね。

hajimismhajimism

An advantage of invoking a Server Action within a Server Component is progressive enhancement - forms work even if JavaScript is disabled on the client.

あ、そうか。そういうメリットもあるな...。

hajimismhajimism

純粋にServer Actionを用いたformのハンズオンがあるのありがたいなあ

hajimismhajimism

To handle type validation, you have a few options. While you can manually validate types, using a type validation library can save you time and effort. For your example, we'll use Zod,

今度はZodがでてきた

hajimismhajimism

const date = new Date().toISOString().split('T')[0];

ここにdate format libraryを紹介するほどではなかったかw
ちゃんと生産性に対して本質的なところでライブラリを紹介しているね

hajimismhajimism

revalidatePathとredirectまで書いて、ひととおりform actionを説明してくれている

hajimismhajimism

Next.js allows you to create Dynamic Route Segments when you don't know the exact segment name and want to create routes based on data. This could be blog post titles, product pages, etc. You can create dynamic route segments by wrapping a folder's name in square brackets. For example, [id], [post] or [slug].

そういえばあんたの説明まだやったなあ

hajimismhajimism

Instead, you can pass id to the formData object with a hidden <input> field. This will allow you to access the id in your Server Action.

丁寧だなあ

hajimismhajimism

いまは流し読みだけど、実際にハンズオンをやりたい章だった!

hajimismhajimism
hajimismhajimism

もはやZodの説明

const InvoiceSchema = z.object({
  id: z.string(),
  customerId: z.string({
    invalid_type_error: 'Please select a customer.',
  }),
  amount: z.coerce
    .number()
    .gt(0, { message: 'Please enter an amount greater than $0.' }),
  status: z.enum(['pending', 'paid'], {
    invalid_type_error: 'Please select an invoice status.',
  }),
  date: z.string(),
});
hajimismhajimism

あ、しかもsafeParseにしてる(この流れでresult型への言及あるか?)

hajimismhajimism

本筋じゃないけど、&&じゃなくて? A : nullなんだな

      {state.errors?.customerId ? (
        <div
          id="customer-error"
          aria-live="polite"
          className="mt-2 text-sm text-red-500"
        >
          {state.errors.customerId.map((error: string) => (
            <p key={error}>{error}</p>
          ))}
        </div>
      ) : null}

hajimismhajimism

いい章ではあったけども、"Improving Accessibility"というタイトルから入った人からするとちょっと期待値とズレてるんじゃないかなーと言う気はした。「Formのバリデーションとエラーハンドリングをちゃんとしました」の章に思えた。

このスクラップは2023/10/27にクローズされました