Laravel+ReactのサイトにZennのブログを表示させる

2024/11/29に公開

LaravelでWebアプリを作るにあたり、まずは所感を掴むためにコーポレートサイトのリニューアルをしました。
そこで今回のZennのTechブログをコーポレートサイトでも表示できるようにしたいと思います。

環境

  • PHP 8.3.12 (cli) (built: Sep 24 2024 18:08:04) (NTS)
  • Laravel Framework 11.33.2
  • react 18.2.0
  • typescript 5.6.3
  • tailwindcss 3.2.1
  • Breeze

参考サイト

Zennの投稿を取得してブログに取り込む(※Next.js)
https://zenn.dev/niiharamegumu/articles/8f00cfdf9753d1
Day.jsの使い方・まとめ
https://zenn.dev/manase/scraps/a82b6e1f18818b
Zenn API Types
https://zenn.dev/kk79it/articles/types-for-zenn-api

手順

ブログ表示用のページ、日付変換用のページ、web.phpでURLの認証が必要です。

1.自分のURLの確認

Zennの記事一覧は下記のURLを確認します。

https://zenn.dev/api/articles?username=【ここに自分のユーザーネーム】&order=latest

自分のユーザーネームはここで確認できます。

2.BlogList.tsxを作成

ページタイトルはコンポーネントにしているので、参考にする人は適宜h1タグなどに書き換えてください。

import { useState, useEffect } from 'react';
import Title from '../PageTitle';
import ConvertDate from './ConvertDate';

export type ZennItem = {
	id: number; // 記事ID
	title: string; // 記事タイトル
	emoji: string; // 記事に関連付けられた絵文字
	path: string; // 記事のURLパス
	published_at: string; // 公開日時 (ISO8601)
};

// 全体レスポンスの型
export type ZennResponse = {
	articles: ZennItem[]; // 記事のリスト
};

export default function BlogList() {
	const [posts, setPosts] = useState<ZennItem[]>([]);
	const [visibleIndexes, setVisibleIndexes] = useState<number[]>([]);

	useEffect(() => {
		const fetchData = async () => {
			try {
				const res = await fetch('/zenn/articles');
				const data: ZennResponse = await res.json(); // 型を明示
				setPosts(data.articles.slice(0, 10)); // 記事リストを保存
			} catch (error) {
				console.error('データ取得エラー:', error);
			}
		};
		fetchData();
	}, []);

	return (
		<>
			<Title title="blog" />
			<p className='text-center'>ZennにてTechブログ記載しています。<br />Xでは日常の感想が多いけど、気軽にお話しできる仕事仲間を募集中です。</p>
			<div className="h-auto w-[calc(100%-16px)] mx-auto flex flex-row flex-wrap gap-2">
				{posts.map((post, index) => (
					<article
						key={post.id}
						className="w-full h-auto md:w-[calc(50%-4px)] bg-slate-200"
					>
						<a
							href={`https://zenn.dev/${post.path}`}
							target="blank"
							rel="noopener noreferrer"
							className="group border-spacing-0.5 flex flex-col gap-2 w-full h-auto px-4 py-2"
						>
							<h2 className="text-2xl group-hover:text-primary">{post.title}</h2>
							<ConvertDate convertDate={post.published_at} />
						</a>
					</article>
				))}
			</div>
		</>
	);
}

3.ConvertDate.tsxを作成

日付をスラッシュで区切る(YYYY/MM/DD)より、ハイフンで区切った方(YYYY-MM-DD)が好みなので、書き換えます。
なんだそのこだわり知らんわって方は飛ばしてください。

import dayjs from 'dayjs';

type Props = {
  convertDate: string | number | Date;
};

export default function ConvertDate({ convertDate }: Props) {
  const publishedAt = dayjs(convertDate).format('YYYY-MM-DD');

  return <time dateTime={convertDate.toString()} className='ext-sm block text-slate-500'>{publishedAt}</time>;
}

4.routes/web.phpで通信設定

Laravelの場合はCORS制限が引っかからないようにroutes/web.phpに表示させたいURLを記載させなければいけません。

use Illuminate\Support\Facades\Http;
Route::get('/zenn/articles', function () {
    $response = Http::get('https://zenn.dev/api/articles?username=【ここに自分のユーザーネーム】&order=latest');
    return response()->json($response->json());
});

5.自分に必要な項目は下記から適宜取得

すごいありがたいファイルを作成してくれている方がいたので、型など参考にしてください。

export type Article = {
id: number;
post_type: "Article";
title: string;
slug: string;
published: boolean;
comments_count: number;
liked_count: number;
body_letters_count: number;
article_type: "tech" | "idea";
emoji: string;
is_suspending_private: boolean;
published_at: string;
body_updated_at: string;
source_repo_updated_at: string;
path: string;
user: User;
publication: Publication | null;
};

上記以外にもUserの型一覧やPublicationの型一覧を書いてくださってます。
自分サイトに合わせて記載するのもアリですね。

Discussion