react-native-mmkv-storage

repository·master·Indexed 23 days ago

https://github.com/ammarahm-ed/react-native-mmkv-storage

A high-performance, JSI-based data storage solution for React Native powered by Tencent's MMKV. Version 12.0.1 supports multiple database instances, full encryption via iOS Keychain and Android Keystore, and reactive hooks like useMMKVStorage and useIndex. It provides both synchronous and asynchronous APIs for storing strings, numbers, booleans, maps, and arrays, along with a Transaction Manager for custom indexing and lifecycle management.

Tokens
17.2K
Snippets
62
Records
106
Agent score
82%

What's inside react-native-mmkv-storage

  1. Features of the Flipper plugin

    master

    The rn-mmkv-storage-flipper plugin provides the following capabilities during development:

    • Logging: Monitor read and write operations as they occur.
    • Live Manipulation: Edit storage values directly within the Flipper interface. If your application uses the useMMKVStorage hook, the state will update automatically in response to these changes.
  2. How the Transaction Manager works

    master

    The Transaction Manager allows you to listen to a value's lifecycle and mutate it on the go. By registering lifecycle functions with your MMKVStorage instance, you can intercept operations such as beforewrite, onwrite, onread, and ondelete. This is useful for building custom indexes, managing lower-level data abstractions, or performing on-the-fly mutations (e.g., injecting timestamps) without manually updating every part of your application logic.

    import { MMKVLoader, useMMKVStorage } from 'react-native-mmkv-storage';
    
    const MMKV = new MMKVLoader().initialize();
    
    // Example: Intercepting a write to log data
    MMKV.transactions.register('object', 'onwrite', ({ key, value }) => {
      console.log('Key:', key, 'Value:', value);
    });
  3. How to handle custom encryption keys with MMKVLoader

    master

    If you choose to manage your own encryption keys instead of using the library's automatic management, you must use MMKVLoader to configure the instance.

    If you change the key used by an existing instance via await MMKV.encryption.changeEncryptionKey("newkey"), you must update the MMKVLoader configuration to use the new key on the next app startup, otherwise the database will not load.

    Example of manual key configuration:

    const MMKV = new MMKVLoader()
      .withEncryption()
      .encryptWithCustomKey("newkey")
      .initialize();
    const MMKV = new MMKVLoader()
      .withEncryption()
      .encryptWithCustomKey("oldkey")
      .initialize();
  4. How MMKV Indexing works

    master

    MMKV provides a multi-layered indexing system.

    1. Instance Indexer: A global index that stores keys for all data types in one place. Use this to check if a key exists regardless of its type or to retrieve all keys in the database.
    2. Type-Specific Indexers: The library maintains separate indices for each data type (strings, numbers, booleans, maps, and arrays). This allows you to query only keys that match a specific data type (e.g., checking if a key exists specifically within the strings index).
  5. How the MMKVLoader class works

    master

    The MMKVLoader class uses a builder pattern to configure and create an MMKV Instance. Instead of passing a large configuration object to a constructor, you chain configuration methods (like withInstanceID, withEncryption, etc.) onto a new MMKVLoader instance and finally call .initialize() to produce the usable MMKV instance. This allows you to create multiple distinct database instances with different settings.

    import { MMKVLoader } from "react-native-mmkv-storage";
    
    const MMKV = new MMKVLoader()
      .withInstanceID('my-id')
      .initialize();
  6. Initialize the MMKVLoader for Async API

    master

    To use the asynchronous API, you must first create and initialize an instance of MMKVLoader.

    Note for older versions: If you are using version <=0.5.3, your very first call to get or set data when the application loads should be an asynchronous call, as the database is initialized during that first call.

    import { MMKVLoader } from "react-native-mmkv-storage";
    
    MMKV = new MMKVLoader().initialize();
  7. Run the React Native example project

    master

    To run the react-native-mmkv-storage-example project, follow these steps:

    1. Start Metro

    Start the Metro JavaScript bundler from the project root:

    npm start
    # or
    yarn start

    2. Build and run the app

    In a new terminal window, run the command for your target platform:

    Android

    npm run android
    # or
    yarn android

    iOS First, ensure CocoaPods dependencies are installed:

    bundle install
    bundle exec pod install

    Then run:

    npm run ios
    # or
    yarn ios
  8. Enable On-the-Fly Mutations

    master

    The beforewrite transaction can be used to inject or modify data before it is actually persisted. This is useful for adding metadata like timestamps to objects automatically.

    const injectTimestamp = record => ({ ...record, timestamp: Date.now() });
    
    MMKV.transactions.register('object', 'beforewrite', ({ key, value }) => {
      if (!key.startsWith('posts.')) return;
      if (!!value.timestamp) return; // Avoid infinite loops if timestamp exists
    
      // Mutate the data by setting a new value with the timestamp
      MMKV.setMapAsync(key, injectTimestamp(value));
    });
  9. Initialize the MMKV instance

    master

    To use the synchronous API, you must first create and initialize an MMKV instance using MMKVLoader.

    Note on Versions:

    • For versions >= 0.5.4, all calls are synchronous and you should not use callbacks.
    • For versions <= 0.5.3, you cannot use synchronous calls with return values at the very start of the app lifecycle; you must use callbacks instead.
  10. Encrypt an existing MMKV instance

    master

    You can encrypt an already created MMKV instance without destroying it. There are three ways to approach this:

    1. Automatic (Recommended): Let the library generate, store, and manage a strong password automatically. This is the smoothest approach as you won't need to update your MMKVLoader configuration later.
    2. Custom Password: Provide your own string as the encryption key.
    3. Secure Storage: Provide a custom password and instruct the library to store that key in secure storage.

    Note: If you use a custom key and later change it, you must update your MMKVLoader configuration on the next app startup, or the database will fail to load.