A React hook for syncing state with localStorage
npm install @rm-hull/use-local-storageA type-safe React hook for syncing state with localStorage that automatically keeps your data in sync across browser tabs and handles SSR gracefully. Built with Jotai for efficient state management.
Unlike react-use, this library provides:
- True cross-tab synchronization - When you update localStorage in one component/tab, all other instances automatically re-render with the new value, even within the same tab
- Consistent loading states - The isLoading flag helps you handle hydration correctly in SSR scenarios
- Shared state management - Multiple components using the same key share a single atom, preventing unnecessary re-renders
- Simpler API - Returns a single object with value, setValue, and isLoading instead of a tuple
``bash`
npm install @rm-hull/use-local-storageor
yarn add @rm-hull/use-local-storage
`tsx
import { useLocalStorage } from "@rm-hull/use-local-storage";
function Counter() {
const { value = 0, setValue, isLoading, error } = useLocalStorage
if (isLoading) return
return (
Count: {value}
$3
`tsx
interface UserPreferences {
theme: "light" | "dark";
notifications: boolean;
}function Settings() {
const { value: prefs, setValue } =
useLocalStorage("user-prefs");
return (
);
}
`$3
`tsx
interface CartItem {
id: string;
name: string;
quantity: number;
}function ShoppingCart() {
const { value: cart = [], setValue } = useLocalStorage("cart");
const addItem = (item: CartItem) => {
setValue([...cart, item]);
};
const removeItem = (id: string) => {
setValue(cart.filter((item) => item.id !== id));
};
return (
Cart ({cart.length} items)
{cart.map((item) => (
{item.name} x {item.quantity}
))}
);
}
`$3
You can provide a custom serializer to transform the data before it's stored and after it's retrieved. This is useful for encrypting data or transforming it in other ways.
A silly example that reverses the string before writing it to localStorage:
`ts
const reverseSerializer = {
serialize: (value: string) => value.split('').reverse().join(''),
deserialize: (value: string) => value.split('').reverse().join(''),
};const { value } = useLocalStorage('my-key', { serializer: reverseSerializer });
`A more practical use case would be to use a library like crypto-js to encrypt the data before storing it.
Features
- Auto-sync across tabs - Changes in one tab are instantly reflected in others
- Type-safe - Full TypeScript support with generics
- SSR-compatible - Handles server-side rendering gracefully
- Efficient - Uses Jotai for optimized re-renders
- Easy cleanup - Pass
undefined to remove items
- Lightweight - Minimal bundle sizeContributer Guidelines
$3
This project uses Changesets to manage versioning and automated npm publishing.
#### How the release process works
1. Create a changeset on your feature branch
When you’ve made changes you want to release, first create a new branch (not on
main):
`bash
git checkout -b feature/my-change
` Make your changes, then run:
`bash
yarn changeset
` You’ll be prompted to:
- Choose the type of version bump (patch, minor, or major)
- Write a short summary of the change
This command creates a markdown file in the
.changeset/ directory describing your upcoming release.2. Commit and push your feature branch
`bash
git add .changeset
git commit -m "Add changeset for upcoming release"
git push -u origin feature/my-change
`3. Merge the feature branch into
main - Once your PR is reviewed, merge it into
main. The .changeset file must be present in main for the next step.4. Automatic version bump and publish
- When changes are pushed to
main, GitHub Actions will automatically: - Build the package
- Apply version bumps based on the
.changeset file
- Update the changelog
- Publish the new version to npm as @rm-hull/use-local-storage5. That's it!
Your package is now live on npm with an updated version and changelog.
---
#### Notes
- The npm publish step is automated via GitHub Actions (
.github/workflows/release.yml).
- Ensure your NPM_TOKEN secret is configured in the repository settings under Settings → Secrets → Actions.
- Changesets should always be created on feature branches, not directly on main.
- No pull requests are created for version bumps; merging your feature branch into main` triggers the release automatically.