← Back
Edit Post
Title
Description
Shareable filter/sort state, preserving params on update, cycle button with optimistic UI.
Content
Markdown supported
# URL State with searchParams URL search parameters provide shareable, bookmarkable state that persists across refreshes. ## Reading searchParams From `app/dashboard/_components/PostList.tsx`: ```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); // ... } ``` ## Updating URL State From `app/dashboard/_components/PostTabs.tsx`: ```tsx 'use client'; export function PostTabs() { const searchParams = useSearchParams(); const router = useRouter(); const currentTab = searchParams.get('filter') ?? 'all'; const currentSort = searchParams.get('sort') ?? 'newest'; function tabAction(value: string) { // Preserve other params when updating one router.push(`/dashboard?filter=${value}&sort=${currentSort}`); } return <TabList activeTab={currentTab} changeAction={tabAction} />; } ``` ## Cycle Button with Optimistic State From `app/dashboard/_components/SortButton.tsx`—a button that cycles through options: ```tsx 'use client'; const sortOptions = [ { icon: ArrowUpDown, label: 'Newest', value: 'newest' }, { icon: ArrowDownUp, label: 'Oldest', value: 'oldest' }, { icon: ArrowDownAZ, label: 'Title', value: 'title' }, ]; export function SortButton() { const searchParams = useSearchParams(); const router = useRouter(); const currentSort = searchParams.get('sort') ?? 'newest'; const currentFilter = searchParams.get('filter') ?? 'all'; const [optimisticSort, setOptimisticSort] = useOptimistic(currentSort); const [isPending, startTransition] = useTransition(); const currentIndex = sortOptions.findIndex(opt => opt.value === optimisticSort); const nextIndex = (currentIndex + 1) % sortOptions.length; const nextSort = sortOptions[nextIndex].value; function sortAction() { startTransition(() => { setOptimisticSort(nextSort); router.push(`/dashboard?filter=${currentFilter}&sort=${nextSort}`); }); } return ( <Button onClick={sortAction} disabled={isPending}> {sortOptions[currentIndex].label} </Button> ); } ``` URL state works with browser history and makes pages shareable—`/dashboard?filter=drafts&sort=title` shows exactly that view.
Published
Save Changes
Cancel