Freshで全ページ共通のサイドバーを作る
作成日
更新日
ポイント
_layout.tsx
にはHandler
は定義できない- しかしDeno Fresh のレイアウトで非同期処理してる!
- これはサーバーサイドの処理らしい。
- これでよくね?
_app.tsx
にもHandler
は定義できない_middleware.tsx
から_app.tsx
に持っていくことはできるけど本来の使い方ではない
共通化できる部分
_app.tsx
で共通 Sidebar を組み込むSidebar.tsx
コンポーネントを用意する
全てのページで書かないといけない?
- 各ページで共通データを注入
- この書いたデータが
_app.tsx
から取得することができる。
export const handler: Handlers = {
async GET(_req, ctx) {
const common = await getCommonPageData();
return ctx.render({ ...common });
},
};
routes/_layout.tsx
について
routes/_layout.tsx
ファイルを用意していたけれど、このファイルの役割は index.tsx
ページと about.tsx
ページといった routes
の配下に適用される。
次の _layout.tsx
ファイルをみつけたら、そちらが優先される。
routes/posts/_layout.tsx
があれば routes/posts/index.tsx
では routes/_layout.tsx
が使われる。
~~なので、基本的に routes/_layout.tsx
は作らないでも良いかもしれない。全てのページで共通化したいコンポーネントは _app.tsx
にかくのが適切そう。
そんなことないかも。
最終
これでいいじゃん。
route/_layout.tsx
import Footer from "../components/Footer.tsx";
import { FreshContext, PageProps } from "$fresh/server.ts";
import { getCommonPageData } from "../utils/getCommonPageData.ts";
import Navigation from "../components/Navigation.tsx";
export default async function Layout(req: Request, ctx: FreshContext) {
const common = await getCommonPageData();
const postMap = common.postMap;
return (
<>
<div class="flex flex-1 w-full">
{/* サイドバー(PCのみ) */}
<aside class="hidden lg:flex flex-col w-64 h-screen fixed top-0 left-0 border-r border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 z-40">
<Navigation postMap={postMap} />
</aside>
<div class="flex-1 lg:ml-64 flex flex-col min-h-screen justify-between">
<div class="w-full p-8">
<ctx.Component />
</div>
<div class="order-last">
<Footer />
</div>
</div>
</div>
</>
);
}
コレにより
- 各ページで共通データを注入なんてしなくて良い
結局用意した _layout.tsx
ファイルは
routes/_layout.tsx
トップページ用routes/[category]/_layout.tsx
単一記事用routes/search/_layout.tsx
検索結果画面用
Fresh 1.2 へアップグレード - island の新機能など シグナルとアイランドを使って、どうにかページが変わった時に再読み込みされないサイドバーを作りたい。
- メインコンテンツの方を islandを使えば良いのか
- でもjsがないとみれないってのも困る
- Freshで記事部分をislandにする
- しかしこれもパーマリンクは変わらずに遷移する形
- Deno Fresh のパーシャルかも!
- 正解!
パーシャルを使う
- 全体で partials を有効化する
全体で Partial を有効化する
body
に f-client-nav
を追加する。
routes/_app.tsx
export default function App(props: FreshContext) {
return (
<html data-theme={theme}>
{/* body 内でパーシャルを有効化する */}
<body class="bg-background" f-client-nav>
<Component />
</body>
</html>
);
}
記事部分を Partial で囲う
記事のコンテンツ部分をPartialで囲う。この部分は変更される部分になる。
/routes/_layout.tsx
import Footer from "../components/Footer.tsx";
import { FreshContext } from "$fresh/server.ts";
import { getCommonPageData } from "../utils/getCommonPageData.ts";
import Navigation from "../components/Navigation.tsx";
import Header from "../components/Header.tsx";
import { Partial } from "$fresh/runtime.ts";
export default async function Layout(req: Request, ctx: FreshContext) {
const common = await getCommonPageData();
const postMap = common.postMap;
return (
<>
<div class="flex flex-1 w-full">
<Header />
{/* サイドバー(PCのみ) */}
<aside class="hidden lg:flex flex-col w-64 h-screen fixed top-0 left-0 border-r border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 z-40">
<Navigation postMap={postMap} />
</aside>
<div class="flex-1 lg:ml-64 flex flex-col min-h-screen justify-between">
<div class="w-full p-8">
<Partial name="content"> {/* ここに Partial を追加 */}
<ctx.Component />
</Partial>
</div>
<div class="order-last">
<Footer />
</div>
</div>
</div>
</>
);
}
これで一応サイドバーは画面遷移後もそのままになった。
f-partial
リンクに f-partial
をつけるって書いてるけど、つけると動かなくなる。nameが違うのかな?
<a
href={`/${category.name}/${post.slug}`}
class="text-blue-600 hover:underline"
f-partial="content"
>
{post.title}
</a>
これはよくわからん。けど書かなければちゃんと動く。何指定するのかわからん...
結論
Deno Fresh のパーシャルを使おう!

公開日
更新日