【第4回】Wiki一覧と詳細画面を作る〜情報の整理と見返しやすさを意識して〜

wiki管理アプリ作成

こんにちは。前回は、個人向けアプリに追加したWiki機能のうち、「記事の登録・更新・削除」機能について紹介しました。 今回はその続きとして、「Wikiの一覧表示」と「詳細画面」の実装についてご紹介します。

パスワード管理の記事は以下を参照してください。

【第1回】なぜ自分でパスワード管理アプリを作ったのか?〜40代エンジニアの試行錯誤〜

【第1回】の記事は以下を参照してください。

【第1回】なぜWiki機能を追加しようと思ったのか?〜40代エンジニアがCodeXに挑む理由〜

【第2回】の記事は以下を参照してください。

【第2回】Wikiテーブルの追加とダッシュボードの改修

【第3回】の記事は以下を参照してください。

【第3回】Wiki記事の登録・更新機能を実装する〜個人アプリに柔軟な知識管理を〜

一覧画面の実装 /app/src/app/wikis/page.tsx

Wiki記事が増えてきたとき、「どこに何を書いたか?」をすばやく把握できる一覧画面は不可欠です。

以下は一覧表示のコードです:

    
'use client';
import { useEffect, useState } from 'react';
import Link from 'next/link';
import type { Wiki } from '@/types/wiki';

const WikiListPage = () => {
  const [wikis, setWikis] = useState<Wiki[] | null>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const load = async () => {
      try {
        const res = await fetch('/api/wiki');
        if (!res.ok) throw new Error('読み込み失敗');
        const data: Wiki[] = await res.json();
        setWikis(data);
      } catch (err) {
        setError((err as Error).message);
      }
    };
    load();
  }, []);

  if (error) return <div>読み込みエラー</div>;
  if (!wikis) return <div>読み込み中...</div>;

  return (
    <div className="space-y-4">
      <h1 className="text-2xl font-bold">Wiki一覧</h1>
      <Link href="/wikis/new" className="bg-blue-500 text-white px-4 py-2 rounded">新規作成</Link>
      <ul className="space-y-2">
        {wikis.map((wiki) => (
          <li key={wiki.id} className="border p-4 rounded">
            <Link href={`/wikis/${wiki.id}`} className="font-semibold hover:underline">
              {wiki.title}
            </Link>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default WikiListPage;
    
  

データ取得は useEffect + fetch で行い、状態管理はシンプルに useState で構成しています。 一覧から記事のタイトルをクリックすると、次に紹介する詳細ページへ遷移します。

詳細画面の実装 /app/src/app/wikis/[id]/page.tsx

一覧から記事タイトルをクリックすると、個別記事の詳細が確認できるようになっています。

    
'use client';
import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import type { Wiki } from '@/types/wiki';

const WikiDetailPage = ({ params }: { params: { id: string } }) => {
  const router = useRouter();
  const [wiki, setWiki] = useState<Wiki | null>(null);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const load = async () => {
      try {
        const res = await fetch(`/api/wiki/${params.id}`);
        if (!res.ok) throw new Error('読み込み失敗');
        const data: Wiki = await res.json();
        setWiki(data);
      } catch (err) {
        setError((err as Error).message);
      }
    };
    load();
  }, [params.id]);

  if (error) return <div>読み込みエラー</div>;
  if (!wiki) return <div>読み込み中...</div>;

  return (
    <div className="space-y-4">
      <h1 className="text-2xl font-bold">{wiki.title}</h1>
      <p className="whitespace-pre-wrap border p-4 rounded bg-white">{wiki.content}</p>
      <button onClick={() => router.push(`/wikis/edit/${wiki.id}`)} className="bg-blue-500 text-white px-4 py-2 rounded">編集</button>
    </div>
  );
};

export default WikiDetailPage;
    
  

ポイント

  1. 記事の内容は whitespace-pre-wrap を使って改行を保持
  2. 更新・削除機能:app/wiki/edit/[id]/page.tsx
  3. 編集ボタンでそのまま更新画面へ遷移できる動線を確保
  4. 閲覧→編集→戻るの流れがスムーズになるよう意識しています。

自分専用Wikiを使ってみて

登録・更新・削除・一覧・詳細表示が一通り揃ったことで、「簡易Wiki」としての機能が整いました。 特にローカル環境で使える安心感と、「すぐに書ける・すぐに見返せる」気軽さが、日々の学びやメモを蓄積する強力な土台になってくれます。

次回予告:「使ってみて感じたことと今後の展望」

次回は、ここまで作ってきたWiki機能について、実際の使用感や気づいた改善点、そしてこれからどんな進化を考えているかをご紹介する予定です。

まとめ

今回は、Wiki機能の一覧表示と詳細画面の実装を通して、「情報を整理し、見返せる」仕組みを作りました。

ちょっとした思いつきや技術的なメモを、あとから振り返れる形で残す。 それが継続的な学びにもつながっていきます。

次回も引き続き、ゆるっと開発の記録を綴っていきます。

コメント

0 件のコメント:

コメントを投稿

コメントをお待ちしています。