Next 13 App Router 在 Server Component 取得目前的 pathname 與 searchParams
前言
目前 Server Component 尚未提供可以直接取得 pathname 與 SearchParams 的方式
僅能從最上層的 Page 參數取得
若希望在比較底層的組件可以無腦用,而不是一直由 Page 傳下來的話
現在只有下列解法
轉成 Client 組件,使用 hook usePathname
, useSearchParams
是官方推薦也是比較正規的解法
考慮 SEO 問題的話,可以參考本站文章: ‘use client’ 與 SEO 問題
這裡節錄重點: use client
相當於 Page Router 的 getServerSideProps
。是 SSR 後再到 Client hydration。仍可保有 SEO
使用 header() 取得
使用 x-invoke-query
, x-invoke-path
const header = headers();
const activePath = header.get('x-invoke-path'); // 網址
const query = header.get('x-invoke-query'); // queryString
但根據官方 issue 討論串
部署在 vercel 的話,是拿不到x-invoke-query
, x-invoke-path
的;本機開發則是一定可以取得
這解法最簡單粗暴,但需要部署後確認平台能否正確取得
使用 header() + middleware
- 增加 middleware.ts,在 request 進來時在 header 設上 pathname 與 searchParams
// /middleware.ts
import { NextResponse } from 'next/server';
export function middleware(request: Request) {
// Store current request url in a custom header, which you can read later
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-url', request.url);
return NextResponse.next({
request: {
// Apply new request headers
headers: requestHeaders,
}
});
}
- 在組件裡由 header 取得
// /app/layout.tsx
import { headers } from 'next/headers';
export default function RootLayout() {
const headersList = headers();
// read the custom x-url header
const pathname = headersList.get('x-url') || '';
}
功比較多,但也最穩健
後記
我自己最後選擇第一個轉成 Client 操作
我們的需求是要將 utm 相關資訊都帶進頁面上所有連結裡
同時考量這 Link 組件也會在 Client 使用,並不是只有在 Server 需要處理
裡面還多了 20 多行 js 做判斷
當沒有 searchParams 時,這段 js 第一行就 return 掉了
去 pageSpeed 測試速度,帶 utm 參數額外處理,跑分還比沒帶 utm 的高= =
若真的很介意,希望能在 Server 處理掉所有事的話
那就推薦第 2、3 個解法,若不是部署在 vercel,說不定用 2 就可以輕鬆解決問題了!
最差情況,就第 3 招強塞參數來處理
參考資料
GitHub / [Next 13] Server Component + Layout.tsx - Can’t access the URL / Pathname