// src/components/LivePosts.jsx
import { useEffect, useState } from 'react';
export default function LivePosts() {
const [posts, setPosts] = useState([]);
useEffect(() => {
fetch('/api/posts.json')
.then((r) => r.json())
.then(setPosts);
}, []);
return (
{posts.map((p) => - {p.title}
)}
);
}
---
// src/pages/live.astro
import LivePosts from '../components/LivePosts.jsx';
---
Live Posts
HOW THIS DIFFERS FROM CHALLENGE 1'S FRONTMATTER FETCH:
- Challenge 1's fetch() ran once, at build time, in Astro's
frontmatter - the rendered was already complete, static HTML
before the browser ever loaded the page.
- LivePosts instead fetches /api/posts.json itself, inside a React
useEffect, which only runs once this component is hydrated in the
browser (thanks to client:load). Every time a visitor loads this
page, the fetch happens fresh, in real time, in their own browser.
- The tradeoff named in the chapter is concrete here: Challenge 1
shipped zero JavaScript for its list; LivePosts requires shipping
and hydrating real React code just to get the same-looking list,
but in exchange the data is never frozen at build time.