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 ที่ดีที่สุดครับ