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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@abundiko/rn-local-storage

v1.2.0

Published

Local storage for react native

Readme

@abundiko/rn-local-storage

A lightweight, typed, and reactive local storage hook for React Native, built on top of react-native-mmkv and zustand.

NOTE: use version 1.0.x for react-native-mmkv versions 3.x.x

Installation

npm install @abundiko/rn-local-storage react-native-mmkv zustand
# or
bun add @abundiko/rn-local-storage react-native-mmkv zustand

NOTE

  • if youre using expo, you need to use a development build because react-native-mmkv is not supported in the expo go app

Best Practices

Create Custom Hooks

Avoid using useLocalStorage directly in your components.

Using useLocalStorage directly can lead to:

  • Scattered magic strings (keys).
  • Inconsistent types across the app.
  • Difficulty in refactoring.

Instead, create domain-specific hooks for each storage key.

Example: useLSTheme

// hooks/useLSTheme.ts
import { useLocalStorage } from "@abundiko/rn-local-storage";

type Theme = "light" | "dark";

export const useLSTheme = () => {
  const { item, setItem } = useLocalStorage<Theme>("app-theme", {
    defaultValue: "light",
  });

  return {
    theme: item,
    setTheme: setItem,
  };
};

Usage in Component

// App.tsx
import { View, Text, Button } from "react-native";
import { useLSTheme } from "./hooks/useLSTheme";

export default function App() {
  const { theme, setTheme } = useLSTheme();

  return (
    <View style={{ backgroundColor: theme === "light" ? "#fff" : "#000" }}>
      <Text>Current Theme: {theme}</Text>
      <Button
        title="Toggle Theme"
        onPress={() => setTheme(theme === "light" ? "dark" : "light")}
      />
    </View>
  );
}

Usage Reference

Basic Usage

import { useLocalStorage } from "@abundiko/rn-local-storage";

const { item, setItem, removeItem } = useLocalStorage("my-key", {
  defaultValue: "default value",
});

Typed Storage

type User = {
  id: string;
  name: string;
  age: number;
};

const { item: user, setItem: setUser } = useLocalStorage<User>("user-profile", {
  defaultValue: { id: "1", name: "John", age: 30 },
});

Using Selectors

Use selectors to subscribe to specific parts of the state to optimize performance.

const { item: userName } = useLocalStorage<User, string>("user-profile", {
  defaultValue: { id: "1", name: "John", age: 30 },
  selector: (user) => user.name,
});

Custom Serialization

Disable JSON serialization for simple strings.

const { item, setItem } = useLocalStorage("theme", {
  defaultValue: "light",
  jsonSerialize: false, // Store as raw string
});

Accessing the Storage Instance

Direct synchronous access to react-native-mmkv.

import { storage } from "@abundiko/rn-local-storage";

const value = storage.getString("some-key");
storage.set("some-key", "some-value");

Updating Partial State

Shallow merge updates.

const { updateItem } = useLocalStorage<User>("user-profile", {
  defaultValue: { id: "1", name: "John", age: 30 },
});

updateItem({ age: 31 });

API

useLocalStorage<T, S>(key, options)

  • key: string - The unique key for the storage item.
  • options: UseSessionOptions<T, S>
    • defaultValue: T - The value to use if the key does not exist.
    • jsonSerialize: boolean (default: true) - Enable/disable JSON serialization.
    • selector: (state: T) => S - Optional selector function.

Returns:

  • item: S - The current value.
  • setItem: (newValue: T) => void - Update the value.
  • removeItem: () => void - Remove the item.
  • updateItem: (partial: Partial<T>) => void - Shallow update.

RNLocalStorage<T>(key, options) - Non-Hook Implementation

Use this when you need to access local storage outside of React components (e.g., in utility functions, services, or class instances).

  • key: string - The unique key for the storage item.
  • options: UseSessionOptions<T, T>
    • defaultValue: T - The value to use if the key does not exist.
    • jsonSerialize: boolean (default: true) - Enable/disable JSON serialization.

Returns an object with methods:

  • get: () => T - Get the current value synchronously.
  • set: (newValue: T) => void - Update the value.
  • remove: () => void - Remove the item.
  • update: (partial: Partial<T>) => void - Shallow merge update.
  • subscribe: (callback: (value: T) => void) => () => void - Subscribe to changes. Returns an unsubscribe function.

Non-Hook Usage (Outside Components)

Basic Usage

import { RNLocalStorage } from "@abundiko/rn-local-storage";

// Create an instance
const themeLSValue = RNLocalStorage<"light" | "dark">("app-theme", {
  defaultValue: "light",
});

// Get the current value
const currentTheme = themeLSValue.get();

// Set a new value
themeLSValue.set("dark");

// Remove the value
themeLSValue.remove();

Typed Storage Outside Components

type User = {
  id: string;
  name: string;
  age: number;
};

const userLS = RNLocalStorage<User>("user-profile", {
  defaultValue: { id: "1", name: "John", age: 30 },
});

// Get user
const user = userLS.get();

// Update user
userLS.set({ id: "2", name: "Jane", age: 25 });

// Partial update
userLS.update({ age: 26 });

Subscribe to Changes

const themeLSValue = RNLocalStorage<"light" | "dark">("app-theme", {
  defaultValue: "light",
});

// Subscribe to changes
const unsubscribe = themeLSValue.subscribe((newTheme) => {
  console.log("Theme changed to:", newTheme);
  // Update your app's theme engine, etc.
});

// Later, unsubscribe when no longer needed
unsubscribe();

Example: Theme Service

// services/ThemeService.ts
import { RNLocalStorage } from "@abundiko/rn-local-storage";

type Theme = "light" | "dark";

class ThemeService {
  private themeLS = RNLocalStorage<Theme>("app-theme", {
    defaultValue: "light",
  });

  getTheme(): Theme {
    return this.themeLS.get();
  }

  setTheme(theme: Theme): void {
    this.themeLS.set(theme);
  }

  toggleTheme(): void {
    const current = this.getTheme();
    this.setTheme(current === "light" ? "dark" : "light");
  }

  onThemeChange(callback: (theme: Theme) => void): () => void {
    return this.themeLS.subscribe(callback);
  }
}

export const themeService = new ThemeService();