ammarahm-ed / react-native-mmkv-storage

An ultra fast (0.0002s read/write), small & encrypted mobile key-value storage framework for React Native written in C++ using JSI
https://rnmmkv.now.sh
MIT License
1.56k stars 109 forks source link

Reactotron plugin #349

Open AldoMX opened 4 months ago

AldoMX commented 4 months ago

Hi, I took the Reactotron plugin from here: https://github.com/infinitered/reactotron/blob/master/lib/reactotron-react-native-mmkv/src/reactotron-react-native-mmkv.ts

And updated/adapted it to work with this mmkv package. I didn't open a PR because this was a quick-n-dirty update I made for myself, but I decided to share it in case someone else finds it useful.

// Taken from: https://github.com/infinitered/reactotron/blob/master/lib/reactotron-react-native-mmkv/src/reactotron-react-native-mmkv.ts
import { type MMKVInstance } from 'react-native-mmkv-storage';
import type { ReactotronCore } from 'reactotron-core-client';

export interface MmkvPluginConfig {
  /**
   * MMKV storage instance
   * @example
   * import { MMKVLoader } from "react-native-mmkv-storage"
   * const storage = new MMKVLoader().initialize()
   */
  storage: MMKVInstance;
  /** Storage keys you want to ignore */
  ignore?: string[];
}

/**
 * Reactotron plugin to log MMKV storage changes
 *
 * @example
 * import { MMKVLoader } from 'react-native-mmkv-storage'
 * import type { ReactotronReactNative } from 'reactotron-react-native'
 * // create your storage instance
 * const storage = new MMKVLoader().initialize()
 *
 * // pass your instance to the plugin
 * Reactotron.use(mmkvPlugin<ReactotronReactNative>({ storage }))
 */
export default function mmkvPlugin<Client extends ReactotronCore = ReactotronCore>(config: MmkvPluginConfig) {
  /** This gives us the ability to ignore specific writes for less noise */
  const ignore = config.ignore ?? [];

  const listeners: (() => void)[] = [];

  return (reactotron: Client) => {
    const logDelete = (key: string) => {
      if (ignore.includes(key)) return;
      reactotron.display({
        name: 'MMKV',
        value: { key },
        preview: `Delete "${key}"`,
        important: true,
      });
    };

    const logWrite = (key: string, value?: unknown) => {
      if (ignore.includes(key)) return;
      reactotron.display({
        name: 'MMKV',
        value: { key, value },
        preview: typeof value === 'object' ? `Set "${key}".` : `Set "${key}" to ${JSON.stringify(value)}`,
        important: true,
      });
      return value;
    };

    return {
      onConnect() {
        listeners.push(
          config.storage.transactions.register('_' as never, 'ondelete', logDelete),
          config.storage.transactions.register('string', 'onwrite', logWrite),
          config.storage.transactions.register('number', 'onwrite', logWrite),
          config.storage.transactions.register('object', 'onwrite', logWrite),
          config.storage.transactions.register('array', 'onwrite', logWrite),
          config.storage.transactions.register('boolean', 'onwrite', logWrite),
        );
      },
      onDisconnect() {
        for (const unregister of listeners) {
          unregister();
        }
        listeners.length = 0;
      },
    };
  };
}
pnthach95 commented 3 months ago

Can you create npm package?

AldoMX commented 3 months ago

I cannot create an npm package: transactions.register only allows a single listener per data type, so people which already have other listeners will see unintended side effects if they use this plugin.

I prefer to hand it over to whoever is interested in supporting it.