npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-local-storage-manager

v0.1.2

Published

localStorage manager for React

Downloads

126

Readme

React local storage manager

Easy to use and efficient localStorage wrapper to use in React

When reading value from localStorage:

  • decodes it with JSON.parse
  • validates it with provided function
  • validation function can transform value if needed
  • stores value in memory cache, previous steps won't be ever executed second time without need

Multiple React components will be kept in sync, localStorage values are synchronized between browser tabs

When using it in Next.js on server side it won't throw any errors, it just won't save anything to localStorage as there is no localStorage on server side.

Full TypeScript support!

Small size

Full source code - ~150 lines of code with comments, empty lines, typescript types. After compiling to JS it becomes ~80 lines of code.

Tested really well

Fully covered with tests - much more tests than actual code

Why

Why to have a whole library for localStorage, it seems to simple to do on my own?

  • when setting value in one component, this library makes all components which are using the value to re-render
  • when setting value in one tab, it be be updated in other browser tabs which are using it
  • parsing, encoding and validating json is synchronous operation which may block UI, this library makes sure it happens only when needed, it caches values

In all other solutions there is no mention of how to validate value before using, JSON.parse happens in every component which is using hook.

Alternative libraries and guides does not implement it:

logrocket blog: only one component updated on change, no cache

react-use-localstorage npm package: has tab sync, but only one component updated on change, no cache

usehooks package: only one component updated on change, no cache

usehooks-ts package: almost good, but no cache, no way to update the value without using it

All articles and other implementations I can find are doing it wrong as well

Examples

Check out this example on codesandbox

Another example use case for 'Cart' with zod for validation:

// cart.store.ts
import createLocalStore from 'react-local-storage-manager'
import { z } from "zod"

const CartItem = z.object({
  id: z.number(),
  quantity: z.number(),
})

type CartItem = z.infer<typeof CartItem>

const CartItems = z.array(CartItem)

const store = createLocalStore(
  'cart', // localStorage key
  (data) => CartItems.parse(data), // validation function must return valid value or throw error
  [] // default value (optional)
)

export const useCartItems = store.use

export const addItemToCart = (item: CartItem) => {
  // set can accept data or a callback, just as useState setter
  store.set(items => [...items, item])
}

export const removeItemFromCart = (itemId: CartItem['id']) => {
  store.set(items => items.filter(item => item.id !== itemId))
}

// Product.tsx
import { useCartItems, addItemToCart, removeItemFromCart } from './cart.store.ts'

export const Product = (item: SomeProduct) => {
  const isAdded = useCartItems().some(added => added.id === item)
  
  const addToCart = () => {
    addItemToCart({ id: item.id, quantity: 1 })
  }
  
  const removeFromCart = () => {
    removeItemFromCart(item.id)
  }
  
  return (
    <div>
      ...product info
      <button
        type='button'
        onClick={addToCart}
        disabled={isAdded}
      >
        Add to Cart
      </button>
      <button
        type='button'
        onClick={removeFromCart}
        disabled={!isAdded}
      >
        Remove from Cart
      </button>
    </div>
  )
}

In this example we are storing only id and quantity because it's a good idea to store minimal info possible.

If we stored product name as well, product photos, this info can become stale, better to store id only and fetch fresh info from the API.

In addition, localStorage has limits, allowed size depends on browser.

API overview

import createLocalStore from 'react-local-storage-manager'

// without default value can be `undefined`
const store = createLocalStore('key', validator)

// with default value won't ever be `undefined`
const store2 = createLocalStore('key', validator, defaultValue)

When invoked with 2 arguments value can be undefined, and when invoked with 3 arguments value will always have type of what is returned by validator function.

If validator function throws, the store will use defaultValue if provided or value will be undefined.

Store methods:

  • read no need to use this method, it's exposed just in case

  • get reads a value only once and then gets value from cache

  • set saves a value to localStorage, to cache, accepts data or a callback which returns data

  • remove calls localStorage.removeItem, sets cache to default value or undefined

  • watch accepts event listener to watch for updates, returns function to clear event listener

  • use React hook to use the value

  • destroy removes event listeners of the store which were set implicitly when creating a store