はじめに
最近フロントエンドの話題に振れることがあったので、新しいライブラリを元に感じた事を整理したいと思います。
まず、最近のフロントエンドを見渡すと、素朴にこんな事をに感じました。
- 「Next.jsやNuxtの機能が多すぎて、何がどう動いているのか追いきれない」
- 「TanStackってよく聞くけど、通常の
useStateやuseEffectと何が違うの?」 - 「Astroというフレームワークが話題だけど、Reactと何が違うの?どう使い分けるの?」
単にツール(ライブラリ/フレームワーク)の使い方を覚えるのではなく、「なぜそのライブラリが必要とされているのか」という背後の思想や課題感についてAIに聞きながら、注目を集めている TanStack と Astro を題材に、知っておくべきモダンフロントエンドの基本的な考え方を記載したいと思います。
フロントエンド進化の歴史と「現代の課題」
まず、なぜTanStackやAstroのような技術が登場したのか?
時代ごとの特徴と直面した課題
1. Traditional MPA(Multi-Page Application)時代
サーバーがリクエストごとに新しいHTMLを返していました。
構成はシンプルで良いんですが、転送量が多くページ遷移ごとに画面全体が白くチラつきます。
私がガリガリPGしてた時代です。Ajaxとか、jQueryとか懐かしい。
2. SPA(Single Page Application)時代(React / Vue等の登場)
画面遷移なしでサクサク動くWebアプリを実現するため、ブラウザ側(Client Side)で大量のJavaScriptを実行して描画する構成が主流になりました。
JSのファイルサイズが膨れ上がり、初期表示が重くなり、SEO(検索エンジン最適化)やOGP(Open Graph Protocol)の設定が難しいなどの課題がありました。
私は最初のReactとの出会い方が良くなくて、フロントエンドから一度離れました。
3. フルスタックSSR時代(Next.js / Nuxt等の台頭)
サーバー側でレンダリング(SSR)や静的生成(SSG)を行い、初期表示とSEOの課題を解決しました。
フレームワーク自体の機能が肥大化・ブラックボックス化し、「画面の一部をインタラクティブにしたいだけなのに、全体に重いJSと複雑なビルド設定が必要になる」というオーバースペック感が生じる課題が生まれました。
この「複雑化しすぎた構成を、もう一度シンプルに整理・最適化しよう」という流れの中から登場してきたのが、TanStack と Astro です。
ライブラリ vs フレームワーク の再定義
ここで一度、「ライブラリ」と「フレームワーク」の言葉の整理します。
フレームワーク
- アプリケーション全体の骨組み・ルールを提供します。ルーティング、データ取得、ビルド設定、ディレクトリ構造まで枠組みが決まっています
- 例: Next.js, Nuxt, Angular
- チーム全員で開発ルールを統一しやすい事がメリット
- 自由度が低く、フレームワークの規約や独自仕様を深く学ぶ必要がある(ベンダーロックイン)事がデメリット
ライブラリ
- 「特定の単一機能」だけを提供する部品・ツールです。全体の構成は開発者が自由に決められます
- 例: TanStack Query, Zustand, Axios
- 自由度が高く、既存のプロジェクトに部分導入しやすい事がメリット
- アーキテクチャや組み合わせの設計責任が開発者側にある事がデメリット
現代のトレンドは、「フレームワークにすべてを委ねるのではなく、単機能で堅牢なライブラリを必要な部分だけ組み合わせて使う」 または 「目的(メディア・コーポレート・Webアプリ)に特化した最小限のフレームワークを選ぶ」 という思考にシフトしてるらしい。
TanStackの世界:状態管理とロジックの分離(Headless思考)
TanStackとは?
TanStack(旧 React Query 開発チームが手がけるオープンソース群)は、Web開発における特定の領域(データ取得、テーブル制御、ルーティングなど)に特化したフレームワーク非依存(UI agnostic)のライブラリ集です。
主要なプロダクトは以下
- TanStack Query(非同期データ取得・キャッシュ管理)
- TanStack Table(データテーブルのロジック制御)
- TanStack Router(型安全なルーティング)
なぜ TanStack Query が革新的なのか?
ReactでAPIからデータを取得する際、次のようなコードを書いたことはありませんか?
// 従来(あまり良くない例)
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('/api/user')
.then(res => res.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(err => {
setError(err);
setLoading(false);
});
}, []);
このコードの問題点は、「クライアント自身の状態(Client State)」と「サーバーから取得したデータの状態(Server State)」を混同してしまっている点にあります。
- Client State: モーダルの開閉、ダークモードの切り替えなど、ブラウザ内だけで完結する状態
- Server State: データベースに保存されており、非同期で取得し、キャッシュやネットワーク遅延、他ユーザーによる更新を考慮すべき状態
TanStack Queryは、この 「Server State(サーバー状態)」の管理を専門に行うライブラリ です。
TanStackが教える「Headless UI / Headless Logic」の考え方
TanStackの多くのライブラリ(特に TanStack Table)は、「見た目(HTML/CSS)」を一切提供しません。提供するのは「ロジック(計算・状態変化・並び替えなど)のみ」です。これを Headless(頭部=見た目 がない)と呼びます。
// TanStack Table の概念イメージ
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(), // 並び替えロジック
});
// UI(見た目)はTailwind CSSでもChakra UIでも自由に使用可能
return (
<table>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id} onClick={header.column.getToggleSortingHandler()}>
{flexRender(header.column.columnDef.header, header.getContext())}
</th>
))}
</tr>
))}
</table>
);
なぜHeadlessが良いのか?
特定のUIコンポーネントライブラリに依存してしまうと、デザインシステムの変更やライブラリのアップデート時に大きな壊滅的影響を受けます。「データ制御の複雑なロジックはTanStackに任せ、見た目の装飾はプロジェクト固有のCSSで自由につくる」 という役割分担ができるため、コードが圧倒的に保守しやすくなる。
ただ、残念ながら現在のプロジェクトでは、お客様のご要望により、逆に進もうとしています。
4. Astroの世界:Islands Architectureと「Zero JS」
次に、近年大きな注目を集めているメタフレームワーク Astro について解説。
Astroとは?
Astroは、ブログ、メディアサイト、ECサイト、コーポレートサイトなどの「コンテンツ中心のWebサイト」を非常に高速に構築するために設計されたフレームワークです。
最大のテーマは 「Ship Less JavaScript(ブラウザに送るJSを最小限にする)」 です。
Islands Architecture(アイランド・アーキテクチャ)とは?
従来のNext.jsやNuxtのSPA/SSRモデルでは、画面全体のインタラクティブ性を担保するために、ページ全体を対象とした ハイドレーション(Hydration: HTMLにJSのイベントハンドラを紐付ける処理) が行われていました。
一方、Astroが提唱する Islands Architecture では、Webページを「静的なHTMLの海」と、その中に浮かぶ「動的なJavaScriptの島(Islands)」として捉えます。
Astroの凄さ:コンポーネントの「マルチフレームワーク対応」
Astroの魅力的なポイントは、React、Vue、Svelte、Solidなどのコンポーネントを同じプロジェクト内で混在させて使えることです。
---
// Astroファイル内 (.astro)
import Header from '../components/Header.astro'; // 静的HTML化される
import ReactCounter from '../components/ReactCounter.jsx'; // Reactコンポーネント
import VueCarousel from '../components/VueCarousel.vue'; // Vueコンポーネント
---
<Layout title="Astro Demo">
<!-- JavaScriptゼロ(静的なHTMLとして出力) -->
<Header />
<main>
<!-- 画面に表示されたタイミングで初めてJSを読み込んで動作させる -->
<ReactCounter client:visible />
<!-- ブラウザが暇な時(idle)にJSを読み込む -->
<VueCarousel client:idle />
</main>
</Layout>
ディレクティブによる細かなハイドレーション制御
-
client:load: ページロード時にJSを即座に実行 -
client:visible: ユーザーがスクロールしてその要素が見えたらJSを実行 -
client:media="(max-width: 500px)": 特定の画面サイズ(モバイルなど)の時だけJSを実行
指定しなければ、JavaScriptはブラウザに一切送信されません(デフォルトZero JS)。 これにより、圧倒的なページロード速度と高いLighthouseスコアを実現できます。
Lighthouseスコア
Googleが開発したWebサイトの品質を測定するオープンソースのツールです。Chrome DevToolsに統合されており、誰でも無料で利用できます。
実務で迷わないための「技術選定の軸」
エンジニアがステップアップするために必要なのは、「どれが一番優れているか」という二元論を捨て、プロダクトの性質に応じた「トレードオフの評価」ができることです。
「新しいから」「流行っているから」という理由だけで採用を決めるのではなく、各ツールの強みと弱みを整理して選ぶ必要があります。
用途別・フロントエンド構成比較
| 項目 | Astro | Next.js / Nuxt | Vanilla React / Vite (SPA) |
|---|---|---|---|
| 主な用途 | メディア、ブログ、コーポレート、EC | 複雑なWebアプリ、SaaS、認証必須サイト | 社内管理画面、高度なインタラクティブアプリ |
| レンダリング | 静的メイン + 部分Hydration | SSR / SSG / ISR / Client | クライアントサイド (CSR) |
| JS送信量 | 極小(Zero JS by Default) | 中〜大(全画面のハイドレーション) | 大 |
| 学習コスト | 低〜中 | 高(フルスタックな概念の理解が必要) | 中 |
| 選定の目安 | コンテンツ閲覧が中心のサイト | ユーザー固有のデータ操作が多いサービス | ログイン後の管理画面やツール類 |
どう思考を組み立てるか?
業務で新しい機能を開発したり、技術選定に関わったりするときは、次のステップで考えてみてください。
- まず「この画面で必要なJavaScriptは何か?」を疑う
- 画面全体をReactで組む必要があるか? 静的なHTMLで十分な場所に重いライブラリを挟んでいないか?
- 状態(State)の種類を見極める
- APIから取ってきたデータなら、自前で
useStateを組むのではなく TanStack Query 等のサーバー状態管理ツールに委ねられないか?
- ロジックと見た目(UI)を分離する
- テーブルの複雑なソートやフィルターのロジックをUIコンポーネントの中に直書きしていないか? Headless思考を取り入れられないか?
おわりに
フロントエンドのトレンドは移り変わりが早いと感じてます。しかし、登場するツールが解決しようとしている「本質的な課題」に着目すると、技術の進化には明確なパターンがありそうです。
- TanStack が教えてくれるのは、「ロジックの専門化と、状態の性質(Client vs Server)に応じた適切な切り分け」
- Astro が教えてくれるのは、「過剰なJavaScriptからの脱却と、ユーザー体験(パフォーマンス)に直結する部分的なインタラクティブ化」
フレームワークが「なぜこの設計になっているのか」「どう役割分担されているのか」という構造的な理解を深めていきたいと思います。
参考(感謝)
- AIに聞きながら
