Astro กับ React: ใช้ React Components ใน Astro อย่างถูกต้อง
#astro13 เม.ย. 2569
ทำไมต้องใช้ React ใน Astro
Astro ดีสำหรับ static content แต่บางส่วนต้องการ interactivity ที่ซับซ้อน เช่น form, chart, real-time data ซึ่ง React ทำได้ดี
ติดตั้ง
npx astro add react
สร้าง React Component
// src/components/Counter.tsx
import { useState } from 'react';
interface Props {
initialCount?: number;
}
export default function Counter({ initialCount = 0 }: Props) {
const [count, setCount] = useState(initialCount);
return (
<div className="flex items-center gap-4">
<button
onClick={() => setCount(c => c - 1)}
className="px-4 py-2 bg-red-500 text-white rounded"
>
-
</button>
<span className="text-2xl font-bold">{count}</span>
<button
onClick={() => setCount(c => c + 1)}
className="px-4 py-2 bg-green-500 text-white rounded"
>
+
</button>
</div>
);
}
ใช้ใน Astro Page
---
import Counter from '../components/Counter.tsx';
import StaticInfo from '../components/StaticInfo.tsx';
---
<!-- Static - ไม่มี JS -->
<StaticInfo title="ข้อมูล" />
<!-- Interactive - โหลด JS ทันที -->
<Counter initialCount={5} client:load />
<!-- โหลดเมื่อ idle -->
<Counter client:idle />
<!-- โหลดเมื่อ visible -->
<Counter client:visible />
Passing Data จาก Astro ไป React
---
const posts = await getCollection('blog');
---
<PostList posts={posts} client:load />
// PostList.tsx
interface Post {
slug: string;
data: { title: string; pubDate: Date };
}
export default function PostList({ posts }: { posts: Post[] }) {
const [filter, setFilter] = useState('');
const filtered = posts.filter(p =>
p.data.title.toLowerCase().includes(filter.toLowerCase())
);
return (
<div>
<input
value={filter}
onChange={e => setFilter(e.target.value)}
placeholder="ค้นหา..."
/>
{filtered.map(post => (
<a key={post.slug} href={`/blog/${post.slug}`}>
{post.data.title}
</a>
))}
</div>
);
}
Context ระหว่าง Islands
// ใช้ nanostores สำหรับ shared state
import { atom } from 'nanostores';
export const cartCount = atom(0);
สรุป
การใช้ React ใน Astro ควรใช้เฉพาะส่วนที่ต้องการ interactivity จริงๆ ส่วนที่เป็น static content ให้ render ใน Astro เพื่อ performance ที่ดีที่สุดครับ