# [Learn Next 14 重點整理](https://nextjs.org/learn?utm_source=next-site&utm_medium=navbar&utm_campaign=home)
## [搭配 Chatbun 輔助學習](https://chatbun.ai/chatbots/nextjs_export)
使用方式:簡單來說,這是基於 next 14 官網資料的 ai 聊天機器人,有想知道的就可以直接問它,但資料量不多,所以需要搭配這篇重點整理去問,例如:
next js 的資料夾結構?
next js 如何處理個人驗證?

## 資料夾結構

1. /app: 主要的資料夾
2. /app/lib: 放hooks, utils
3. /app/ui: UI 元件
4. /public: 圖片 靜態資源
5. /scripts/: 資料庫
6. global.css: reset.css 全域 css 規則
7. 條件判斷的 css 可用 clsx 套件
8. 字型 font.ts
9. 圖片 < Image> 元件
10. 如果要優化 外部圖片 or 本地字型 [看這篇最下面](https://nextjs.org/learn/dashboard-app/optimizing-fonts-images)
## 路由
1. 巢狀路由

2. 以 page.tsx 為主軸,例如 /dashboard/page.tsx => 頁面 /dashboard
3. /dashboard 中所有 page 的共用元件,則放在 /dashboard/layout.tsx,dashboard 的子頁面時,共用元件就不需要 re-render ([partial-rendering](https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating#3-partial-rendering))
4. < Link> 元件 切換頁面時有 SPA 的效果,而且在載入 Link 元件時,會同步 prefetch 他的對應頁面,達到效能優化的效果。
5. usePathname 或任何 react 的 hook 都需要在 'use client' 環境使用
6. 可以使用 clsx 套件做 active 的樣式
```typescript
'use client';
import {
UserGroupIcon,
HomeIcon,
DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import clsx from 'clsx';
// ...
export default function NavLinks() {
const pathname = usePathname();
return (
<>
{links.map((link) => {
const LinkIcon = link.icon;
return (
<Link
key={link.name}
href={link.href}
className={clsx(
'flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3',
{
'bg-sky-100 text-blue-600': pathname === link.href,
},
)}
>
<LinkIcon className="w-6" />
<p className="hidden md:block">{link.name}</p>
</Link>
);
})}
</>
);
}
```
## fetching data
1. 使用 React Server Components (server 端接資料),則不需要 API layer
2. 如果在 client 端皆資料的話,則需要 [API layer](https://nextjs.org/learn/dashboard-app/fetching-data#api-layer)
在 server 端撈 sql 的資料步驟
/lib/data.ts
```typescript
export async function fetchRevenue() {
// Add noStore() here prevent the response from being cached.
// This is equivalent to in fetch(..., {cache: 'no-store'}).
try {
// Artificially delay a response for demo purposes.
// Don't do this in real life :)
console.log('Fetching revenue data...');
await new Promise((resolve) => setTimeout(resolve, 3000));
const data = await sql<Revenue>`SELECT * FROM revenue`;
console.log('Data fetch complete after 3 seconds.');
return data.rows;
} catch (error) {
console.error('Database Error:', error);
throw new Error('Failed to fetch revenue data.');
}
}
```
/dashboard/page.tsx
```typescript
// 因為 Page 元件是非同步函示 所以可以等待資料來源
const revenue = await fetchRevenue();
...
<RevenueChart revenue={revenue} />
```
避免 request waterfalls

可利用 Parallel data fetching 解決上述問題 提升效能
```typescript
export async function fetchCardData() {
try {
const invoiceCountPromise = sql`SELECT COUNT(*) FROM invoices`;
const customerCountPromise = sql`SELECT COUNT(*) FROM customers`;
const invoiceStatusPromise = sql`SELECT
SUM(CASE WHEN status = 'paid' THEN amount ELSE 0 END) AS "paid",
SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) AS "pending"
FROM invoices`;
const data = await Promise.all([
invoiceCountPromise,
customerCountPromise,
invoiceStatusPromise,
]);
// ...
}
}
```
## 骨架屏
1. 整頁骨架屏:搭配loading.tsx實作 /dashboard 頁面專屬的骨架屏 (必須放在(overview:檔名隨便)的資料夾中)

2. 元件骨架屏:為了避免 request waterfalls,將元件拆細,便可做到 code split 的效果,並且利用 react Suspense 元件做出骨架屏的效果
```typescript
<Suspense fallback={<LatestInvoicesSkeleton />}>
<LatestInvoices />
</Suspense>
```
- You could stream the whole page like we did with loading.tsx... but that may lead to a longer loading time if one of the components has a slow data fetch.
- You could stream every component individually... but that may lead to UI popping into the screen as it becomes ready.
- You could also create a staggered effect by streaming page sections. But you'll need to create wrapper components.
## 利用 URL 實作搜尋功能
1. usePathname() => 取得全部網址
2. useSearchParams() => 取得 query
3. useRouter() => 切換搜尋列表網址並有 SPA 的效果
4. URLSearchParams => web API
5. use-debounce => debounce 套件
6. 利用上述 client 端取得 server 端的參數 去搜尋資料庫中的資料
[參考這頁 adding-search-and-pagination](https://nextjs.org/learn/dashboard-app/adding-search-and-pagination)
## CRUD
利用 React Server Actions 建立方法 createInvoice
React Server Actions 會創建 post 請求的 api 節點,所以我們不需要手動創建
並且利用 zod 檢查表單型別(server端)
- 利用react server actions 實作新建資料的邏輯
- 在頁面引入後 利用action的 props 觸發方法
`<form action={createInvoice}>`
## 處理錯誤
1. 使用 try catch 處理 server 端的錯誤
2. 使用 error 元件處理所有錯誤頁面(必須是 client component)
3. 使用 notFound(), not-found 元件處理401錯誤
## 表單檢查
- require attr
- server 端使用 zod 驗證表單
## isAuth 檢查
1. 使用 next-auth
2. 被保護的路由只有在 middleware 驗證通過才會 render
3. bcrypt 套件依賴 Node.js (產生密碼用的)
## Meta Data
```htmlembedded
<!--社群軟體分享時會出現的資訊-->
<meta property="og:title" content="Title Here" />
<meta property="og:description" content="Description Here" />
<meta property="og:image" content="image_url_here" />
```
## 結論
優點:
1. 提供了許多好用的 api, component 包含路由、圖片優化等
2. 活用了 react server component 的用法
3. 用資料夾來決定路由的方式在小型專案的情況下非常方便
4. 這次新推出的官方課程算是簡短好上手,相當推薦嘗試看看
缺點:
1. 雖然狀態管理一樣推薦用 redux,但是 Server Components 是一种新的實驗性功能,需要重新考慮如何管理和共享狀態
2. 儘管也有管理元件的概念,但”資料夾決定路由“這件事情在大型專案下的維護性值得觀察