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

@hampfh/use-storage

v1.2.6

Published

Typed persistency storage with reactivity

Downloads

19

Readme

useStorage

Vitest

Store fully typed reactive persistent state, supports both react & react native. useStorage wraps both async storage and redux toolkit allowing the benefits of reactivness and persistency at the same time.

Setup

Install peer dependencies

yarn add zod @reduxjs/toolkit

Define your persistent files at the beginning of your app and wrap the application in the provider

Initialize storage

Make sure that wherever you declare this, it is imported in your entrypoint.

import { Storage, StorageProvider } from "@hampfh/use-storage"

const schema = {
  file: z.object({
    version: z.string(),
    clickCount: z.number()
  }).default({
    version: "1.0.0",
    clickCount: 0
  })
  file2: // other file schema ...
}

Storage({
  schema
})

declare module "@hampfh/use-storage" {
  interface Register {
    schema: typeof schema
  }
}

Usage

Read value

function Component() {
  const { value } = useStorage("file")

  function onClick() {
    console.log(value)
  }

  return <Button onPress={onClick} />
}

Write value

function Component() {
  const { value, merge, write } = useStorage("file")

  async function incrementClick() {
    await merge({
      clickCount: value.clickCount + 1
    })
  }

  async function set() {
    await write({
      version: "1.0.0",
      clickCount: 0
    })
  }

  return (
    <>
      <Text>{value}</Text>
      <Button title="Increment" onPress={incrementClick} />
      <Button title="Set" onPress={set}>
    </>
  )
}

Action on load

There are scenarios where you want to perform an action when a component is loaded. Due to the nature of async storages a value cannot be provided instantly and will therefore provide undefined. In such case we can wait for the file to be instantiated

function Component() {
  const { initialized, value, write } = useStorage("file")

  useEffect(() => {
    if (initialized) {
      // Now value is loaded, do something with it
      console.log(value)
    }
  }, [initialized])

  return null
}

API

Storage

The storage function is used to initialize the library and all typings. Call this function at the beginning of your app.

Storage({
  schema: Record<string, z.ZodObject>,
  adapter: StorageAdapter
})

useStorage hook

const { initialized, value, write, merge, clear } = useStorage(file: string)

This hook like any other must be called within a component and requires StorageProvider to be wrapped around.

Fields

initialized: value indicating if the state has been loaded or not
value: The selected file's state
write: Set the selected file's state, must provide entire file state
merge: Merge the selected file's state, can provide partial file state
clear: Clear the selected file's state, sets to default state

readStorageFile

readStorageFile(file: string): Promise<file_state | null>

writeStorageFile

writeStorageFile(file: string, newState: sub_state): Promise<boolean>

clearStorageFile

clearStorageFile(file: string): Promise<void>

StorageProvider

Provider component for useStorage, must be wrapped around the entire app.

Adapters

Adapters are provide the logic for reading and writing to storeage. Any new adapter can easily be added by implementing the interface. As of now there are three adapters, one for react native, react and the a BaseAdapter. The BaseAdapter is used unless anything else is provided. The BaseAdapter is NOT suited for production and won't persist state.

AsyncStorage (react native)

Peer dependency

To use this adapter install the async storage library for react native

yarn add @react-native-async-storage/async-storage
import { AsyncStorageAdapter } from "@hampfh/use-storage"

Storage({
  schema,
  adapter: new AsyncStorageAdapter()
})

LocalStorageAdapter (web)

import { LocalStorageAdapter } from "@hampfh/use-storage"

Storage({
  schema,
  adapter: new LocalStorageAdapter({
    prefix?: string // Prefix each key with the provided string
    base64?: boolean // Encode values when writing to local storage
  })
})