@rm-hull/use-local-storage
v0.3.4
Published
A React hook for syncing state with localStorage
Downloads
483
Readme
use-local-storage
A 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.
Why use this instead of react-use's useLocalStorage?
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
isLoadingflag 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, andisLoadinginstead of a tuple
Quick Start
npm install @rm-hull/use-local-storage
# or
yarn add @rm-hull/use-local-storageUsage Examples
Basic Counter
import { useLocalStorage } from "@rm-hull/use-local-storage";
function Counter() {
const { value = 0, setValue, isLoading, error } = useLocalStorage<number>("counter");
if (isLoading) return <div>Loading...</div>;
if (!!error) return <div>Error: {error.message}</div>;
return (
<div>
<p>Count: {value}</p>
<button onClick={() => setValue(value + 1)}>Increment</button>
<button onClick={() => setValue(undefined)}>Clear</button>
</div>
);
}User Preferences
interface UserPreferences {
theme: "light" | "dark";
notifications: boolean;
}
function Settings() {
const { value: prefs, setValue } =
useLocalStorage<UserPreferences>("user-prefs");
return (
<div>
<label>
<input
type="checkbox"
checked={prefs?.theme === "dark"}
onChange={(e) =>
setValue({
...prefs,
theme: e.target.checked ? "dark" : "light",
})
}
/>
Dark Mode
</label>
</div>
);
}Shopping Cart
interface CartItem {
id: string;
name: string;
quantity: number;
}
function ShoppingCart() {
const { value: cart = [], setValue } = useLocalStorage<CartItem[]>("cart");
const addItem = (item: CartItem) => {
setValue([...cart, item]);
};
const removeItem = (id: string) => {
setValue(cart.filter((item) => item.id !== id));
};
return (
<div>
<h2>Cart ({cart.length} items)</h2>
{cart.map((item) => (
<div key={item.id}>
{item.name} x {item.quantity}
<button onClick={() => removeItem(item.id)}>Remove</button>
</div>
))}
</div>
);
}Custom Serializer
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:
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
undefinedto remove items - Lightweight - Minimal bundle size
Contributer Guidelines
Releasing a New Version
This project uses Changesets to manage versioning and automated npm publishing.
How the release process works
Create a changeset on your feature branch
When you’ve made changes you want to release, first create a new branch (not on
main):git checkout -b feature/my-changeMake your changes, then run:
yarn changesetYou’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.Commit and push your feature branch
git add .changeset git commit -m "Add changeset for upcoming release" git push -u origin feature/my-changeMerge the feature branch into
main- Once your PR is reviewed, merge it into
main. The.changesetfile must be present inmainfor the next step.
- Once your PR is reviewed, merge it into
Automatic version bump and publish
When changes are pushed to
main, GitHub Actions will automatically:- Build the package
- Apply version bumps based on the
.changesetfile - Update the changelog
- Publish the new version to npm as
@rm-hull/use-local-storage
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_TOKENsecret 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
maintriggers the release automatically.
