Shareable filters
Put filters in the URL — /blog?tag=recipe — and they survive refreshes, work with the back button and can be shared. Pages receive them as search params.
searchParams on the server, links to change them
import Link from "next/link";
import { getPosts } from "@/lib/posts";
export default async function Blog({ searchParams }) {
const { tag } = await searchParams;
const posts = await getPosts({ tag });
return (
<>
<nav>
<Link href="/blog">All</Link> · <Link href="/blog?tag=recipe">Recipes</Link> · <Link href="/blog?tag=news">News</Link>
</nav>
<ul>{posts.map((p) => <li key={p.slug}>{p.title}</li>)}</ul>
</>
);
}- In Client Components, read them with useSearchParams(); update with router.push("?q=…").
- Reading searchParams makes the page render per request (it depends on the URL).
- Validate values: anything can be typed into a URL.