Shareable filter/sort state, preserving params on update, cycle button with optimistic UI.
URL search parameters provide shareable, bookmarkable state that persists across refreshes.
From app/dashboard/_components/PostList.tsx:
const filterSchema = z.enum(['all', 'published', 'drafts', 'archived']).catch('all');
const sortSchema = z.enum(['newest', 'oldest', 'title']).catch('newest');
export async function PostList({ searchParams }) {
const { filter, sort } = await searchParams;
const validFilter = filterSchema.parse(filter);
const validSort = sortSchema.parse(sort);
const posts = await getPosts(validFilter, validSort);
// ...
}From app/dashboard/_components/PostTabs.tsx:
'use client';
export function PostTabs() {
const searchParams = useSearchParams();
const router = useRouter();
const currentTab = searchParams.get('filter'
From app/dashboard/_components/SortButton.tsx—a button that cycles through options:
'use client';
const sortOptions = [
{ icon: ArrowUpDown, label: 'Newest', value: 'newest' },
{ icon: ArrowDownUp, label: 'Oldest', value:
URL state works with browser history and makes pages shareable—/dashboard?filter=drafts&sort=title shows exactly that view.