Client State vs URL State vs LocalStorage: The Complete Guide
January 2025 · Derick Zr · 4 minutes read
I built a product configurator that lost the user's selections on refresh.
Customer picks the color, size, and specs. They refresh the page. Everything resets.
I was storing it all in React state.
Wrong choice. Here's what I learned about where to actually store state.
The Three Types of State
1. Client State (React useState)
- Lives only in memory while your component is mounted
- Resets when you refresh the page
- Perfect for: UI interactions, temporary form data, modal states
2. URL State (Query Parameters)
- Lives in the browser's address bar
- Shareable - send the URL to someone else and they see the same state
- Perfect for: filters, search queries, configuration that should be bookmarkable
3. LocalStorage State
- Persists across browser sessions on the same device
- Not shareable - only visible to the current user on their device
- Perfect for: user preferences, theme settings, draft content
Interactive Examples
Try these demos to see the differences in action:
Example 1: Simple Counter
This counter demonstrates all three approaches. Notice how each behaves differently when you refresh the page or copy the URL.
React State Counter
Resets to 0 when you refresh the page
Try refreshing the page - this counter will reset to 0
URL State Counter
Stored in the URL, shareable and bookmarkable
Watch the URL change as you click. Copy the URL and share it - others will see the same count!
LocalStorage Counter
Persists across browser sessions on this device
Close the browser and come back - this counter will remember its value
Key Insights:
- React State: Fast and simple, but lost on refresh
- URL State: Shareable and bookmarkable, but updates the browser history
- LocalStorage: Persists across sessions, but can't be shared
Example 2: Phone Options
On a product page, people pick the specs they want and can share the exact configuration if they want.
Phone Options
Configure a phone and share your exact selection via URL
Your Configuration
Try this: Configure your ideal phone, then copy the URL and open it in a new tab. Your exact configuration will be preserved! This is perfect for e-commerce where customers want to share their product selections.
Why URL State Wins Here:
- Customer can share their exact configuration via URL
- Bookmarkable for later purchase
- Works across devices if they send themselves the link
- SEO-friendly if you have different pricing per configuration
Decision Framework
Here's how to choose:
Use React State When:
- Temporary UI state (modals, dropdowns, form inputs)
- State only matters while user is actively interacting
- Performance is critical (no serialization overhead)
Avoid when:
- You need state to survive page refresh
- Users might want to bookmark or share the state
Use URL State When:
- State should be shareable via URL
- State should be bookmarkable
- Filters, search queries, or configurations
- SEO matters for different state combinations
Avoid when:
- State is personal/private
- State is complex objects (keep URLs clean)
Use LocalStorage When:
- User preferences that should persist
- Draft content or "work in progress" data
- Theme settings, language preferences
- Shopping cart contents (until checkout)
Avoid when:
- State needs to be shared between users
- State is critical (localStorage can be cleared)
Implementation Patterns
URL State Pattern
const [filters, setFilters] = useUrlState({
category: 'all',
priceRange: '0-100'
})
// Automatically syncs with ?category=electronics&priceRange=50-200LocalStorage Pattern
const [theme, setTheme] = useLocalStorage('theme', 'light')
// Persists across browser sessionsWhen to Combine Them
Sometimes you need multiple types:
// URL for shareable filters
const [filters, setFilters] = useUrlState({ category: 'all' })
// LocalStorage for user preferences
const [viewMode, setViewMode] = useLocalStorage('viewMode', 'grid')
// React state for UI interactions
const [isModalOpen, setIsModalOpen] = useState(false)Common Mistakes
Putting everything in React state
// Wrong: Lost on refresh, can't be shared
const [productConfig, setProductConfig] = useState({
color: 'red',
size: 'large',
model: 'pro'
})Putting UI state in URL
// Wrong: Clutters URL, not bookmarkable in meaningful way
const [isModalOpen, setIsModalOpen] = useUrlState('modalOpen', false)Putting personal preferences in URL
// Wrong: Not personal, gets shared when URL is copied
const [darkMode, setDarkMode] = useUrlState('darkMode', false)Key Takeaways
- React State: Fast, temporary, component-scoped
- URL State: Shareable, bookmarkable, SEO-friendly
- LocalStorage: Personal, persistent, device-scoped
Use the right tool for the job. Your users will thank you.
Start with React state. Promote to URL or localStorage only when you need it.