As web applications continue to evolve into robust experiences resembling native apps, the need for local data storage on the client-side becomes increasingly important. Technologies like cookies, localStorage, and sessionStorage provide frontend developers with various options for temporarily caching data within the browser.
In this article, we'll explore the key differences between these three storage mechanisms and how each can be leveraged appropriately based on an application's specific data needs. By understanding the capabilities and limitations of each, you can architect your client-side code for optimal performance while avoiding common pitfalls.
Cookies: The Sticky Notes of the Web
Photo by Christina Branco on Unsplash
Cookies have been around since the early days of the web and remain one of the most basic forms of client-side storage. Primarily used for authentication, cookies allow servers to uniquely identify returning users by storing a small amount of data on their machine.
However, cookies come with limitations. Each cookie can only hold up to 4kb of data formatted as a single string, making them ill-suited for structured or large datasets. Additionally, every request to the server will attach all cookie headers, increasing bandwidth consumption.
For these reasons, cookies are best used sparingly - to store things like user IDs, preferences, or session tokens. Libraries exist to simplify encoding/decoding of cookie values to dictionary formats.
// Setting a cookie without a library
document.cookie = "username=JohnDoe; expires=Thu, 18 Dec 2023 12:00:00 UTC; path=/";
// Using a library to set a cookie
Cookies.set('username', 'JohnDoe', { expires: 7, path: '/' });
Libraries like js-cookie
provide convenient methods for getting and setting cookies, dealing with the nuances of string parsing under the hood.
localStorage: The Whiteboard
localStorage is like having a whiteboard in your home. You can write down reminders that stay there until you erase them. localStorage provides a more robust alternative to cookies for locally caching larger amounts of structured data. Values are stored as key-value pairs that can be accessed on all pages of a domain, persisting even when the browser is closed.
This makes localStorage ideal for caching dynamic responses, application states, or content likely to be reused across sessions. Developers have up to 5-10mb of storage per origin, though browser support varies.
// Setting an item in localStorage
localStorage.setItem('favoriteColor', 'blue');
// Getting that item back
let favoriteColor = localStorage.getItem('favoriteColor');
SessionStorage: The Notepad
Similar to localStorage, sessionStorage (up to 5mb) also uses a key-value data structure but will only persist for the lifetime of the browser tab or window it was created in. Data is removed once the tab closes.
Well-suited for multi-step workflows, sessionStorage enables locally caching intermediate states or contextual data meant to enhance the user experience on a single page load.
// Setting an item in sessionStorage
sessionStorage.setItem('toDoList', 'Buy milk');
// Getting that item back
let toDoList = sessionStorage.getItem('toDoList');
Managing Your Storage
To maintain organized and efficient data stores, periodic cleaning can be helpful. Through the Storage
API, you can remove individual items as well as empty the entirety of cached data:
-
Remove a specific item:
localStorage.removeItem('favoriteColor');
-
Clear everything:
localStorage.clear();
The same methods apply for sessionStorage.
Using Storage in React with Hooks
Photo by Lautaro Andreani on Unsplash
React's hooks allow you to interact with local storage in a more intuitive way, abstracting complex operations into simple function calls. Here's how you can create a custom hook to manage localStorage in your React apps:
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
// Parse stored json or if none return initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// If error also return initialValue
console.error(error);
return initialValue;
}
});
// Return a wrapped version of useState's setter function
// This ensures we're always storing a string
const setValue = (value) => {
try {
// Allow value to be a function so we have the same API as useState
const valueToStore =
value instanceof Function ? value(storedValue) : value;
// Save state
setStoredValue(valueToStore);
// Save to local storage
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
// A more advanced implementation would handle the error case
console.error(error);
}
};
useEffect(() => {
setValue(storedValue);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [key, storedValue]);
return [storedValue, setValue];
}
// Example usage of the hook in a component
function App() {
const [name, setName] = useLocalStorage('name', 'Alice');
return (
<div>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
);
}
export default App;
The Future: Secure Alternatives
While cookies, localStorage and sessionStorage empower versatile application functionality through client-side data caching, several security limitations remain that developers must carefully consider.
As currently implemented, any JavaScript loaded onto a page possesses the ability to access stored values, posing risks if sensitive information is involved. No built-in protection from unauthorized retrieval or modification exists.
Recognizing such concerns, upcoming standards propose enhancements strengthening data confidentiality.
In the meantime, best practices involve judiciously avoiding PII or credential placement within browsers' storage APIs directly. Leverage server-side sessions instead when appropriate. Similarly, exercise caution with third-party code integration to minimize exposure.
Thank you for reading.
If you found this helpful, be sure to check out the rest of my page for additional deep dives covering front-end performance, accessibility techniques and more!
Top comments (0)