react-native-mmkv 1.3.3 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -127,6 +127,9 @@ const isMmkvFastAsf = storage.getBoolean('is-mmkv-fast-asf') // true
127
127
  ### Keys
128
128
 
129
129
  ```js
130
+ // checking if a specific key exists
131
+ const hasUsername = storage.contains('user.name')
132
+
130
133
  // getting all keys
131
134
  const keys = storage.getAllKeys() // ['user.name', 'user.age', 'is-mmkv-fast-asf']
132
135
 
@@ -145,65 +148,26 @@ const user = {
145
148
  age: 21
146
149
  }
147
150
 
151
+ // Serialize the object into a JSON string
148
152
  storage.set('user', JSON.stringify(user))
149
153
 
154
+ // Deserialize the JSON string into an object
150
155
  const jsonUser = storage.getString('user') // { 'username': 'Marc', 'age': 21 }
151
156
  const userObject = JSON.parse(jsonUser)
152
157
  ```
153
158
 
154
- ## Migrate from AsyncStorage
159
+ ## Documentation
155
160
 
156
- See [#52](https://github.com/mrousavy/react-native-mmkv/issues/52) for instructions on how to safely migrate your existing AsyncStorage database to MMKV.
161
+ * [Hooks](./docs/HOOKS.md)
162
+ * [Value-change Listeners](./docs/LISTENERS.md)
163
+ * [Migrate from AsyncStorage](./docs/MIGRATE_FROM_ASYNC_STORAGE.md)
164
+ * [Using MMKV with redux-persis](./docs/WRAPPER_REDUX.md)
165
+ * [Using MMKV with mobx-persist-storage](./docs/WRAPPER_MOBX.md)
157
166
 
158
167
  ## Limitations
159
168
 
160
169
  As the library uses JSI for synchronous native methods access, remote debugging (e.g. with Chrome) is no longer possible. Instead, you should use [Flipper](https://fbflipper.com).
161
170
 
162
- ## redux-persist
163
-
164
- If you want to use MMKV with [redux-persist](https://github.com/rt2zz/redux-persist), create the following `storage` object:
165
-
166
- ```ts
167
- import { Storage } from 'redux-persist'
168
-
169
- const storage = new MMKV()
170
-
171
- export const reduxStorage: Storage = {
172
- setItem: (key, value) => {
173
- storage.set(key, value)
174
- return Promise.resolve(true)
175
- },
176
- getItem: (key) => {
177
- const value = storage.getString(key)
178
- return Promise.resolve(value)
179
- },
180
- removeItem: (key) => {
181
- storage.delete(key)
182
- return Promise.resolve()
183
- },
184
- }
185
- ```
186
-
187
- ## mobx-persist-store
188
-
189
- If you want to use MMKV with [mobx-persist-store](https://github.com/quarrant/mobx-persist-store), create the following `storage` object:
190
-
191
- ```ts
192
- import { configurePersistable } from 'mobx-persist-store'
193
-
194
- const storage = new MMKV()
195
-
196
- configurePersistable({
197
- storage: {
198
- setItem: (key, data) => storage.set(key, data),
199
- getItem: (key) => storage.getString(key),
200
- removeItem: (key) => storage.delete(key),
201
- },
202
- })
203
- ```
204
-
205
- For more information, check out [kanzitelli/rnn-starter](https://github.com/kanzitelli/rnn-starter).
206
-
207
171
  ## Adopting at scale
208
172
 
209
173
  react-native-mmkv is provided _as is_, I work on it in my free time.
@@ -59,7 +59,7 @@ android {
59
59
  }
60
60
 
61
61
  packagingOptions {
62
- excludes = ["**/libc++_shared.so", "**/libfbjni.so", "**/libjsi.so"]
62
+ excludes = ["**/libc++_shared.so", "**/libfbjni.so", "**/libreactnativejni.so", "**/libjsi.so", "**/MANIFEST.MF"]
63
63
  }
64
64
 
65
65
  buildTypes {
@@ -27,6 +27,7 @@ std::vector<jsi::PropNameID> MmkvHostObject::getPropertyNames(jsi::Runtime& rt)
27
27
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getBoolean")));
28
28
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getString")));
29
29
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getNumber")));
30
+ result.push_back(jsi::PropNameID::forUtf8(rt, std::string("contains")));
30
31
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("delete")));
31
32
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getAllKeys")));
32
33
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("deleteAll")));
@@ -118,6 +119,23 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
118
119
  });
119
120
  }
120
121
 
122
+ if (propName == "contains") {
123
+ // MMKV.contains(key: string)
124
+ return jsi::Function::createFromHostFunction(runtime,
125
+ jsi::PropNameID::forAscii(runtime, funcName),
126
+ 1, // key
127
+ [this](jsi::Runtime& runtime,
128
+ const jsi::Value& thisValue,
129
+ const jsi::Value* arguments,
130
+ size_t count) -> jsi::Value {
131
+ if (!arguments[0].isString()) throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
132
+ auto keyName = arguments[0].getString(runtime).utf8(runtime);
133
+
134
+ bool containsKey = instance->containsKey(keyName);
135
+ return jsi::Value(containsKey);
136
+ });
137
+ }
138
+
121
139
  if (propName == "delete") {
122
140
  // MMKV.delete(key: string)
123
141
  return jsi::Function::createFromHostFunction(runtime,
@@ -24,6 +24,7 @@ std::vector<jsi::PropNameID> MmkvHostObject::getPropertyNames(jsi::Runtime& rt)
24
24
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getBoolean")));
25
25
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getString")));
26
26
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getNumber")));
27
+ result.push_back(jsi::PropNameID::forUtf8(rt, std::string("contains")));
27
28
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("delete")));
28
29
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getAllKeys")));
29
30
  result.push_back(jsi::PropNameID::forUtf8(rt, std::string("deleteAll")));
@@ -113,7 +114,24 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
113
114
  return jsi::Value(value);
114
115
  });
115
116
  }
116
-
117
+
118
+ if (propName == "contains") {
119
+ // MMKV.contains(key: string)
120
+ return jsi::Function::createFromHostFunction(runtime,
121
+ jsi::PropNameID::forAscii(runtime, funcName),
122
+ 1, // key
123
+ [this](jsi::Runtime& runtime,
124
+ const jsi::Value& thisValue,
125
+ const jsi::Value* arguments,
126
+ size_t count) -> jsi::Value {
127
+ if (!arguments[0].isString()) throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
128
+
129
+ auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime));
130
+ bool containsKey = [instance containsKey:keyName];
131
+ return jsi::Value(containsKey);
132
+ });
133
+ }
134
+
117
135
  if (propName == "delete") {
118
136
  // MMKV.delete(key: string)
119
137
  return jsi::Function::createFromHostFunction(runtime,
@@ -124,7 +142,7 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
124
142
  const jsi::Value* arguments,
125
143
  size_t count) -> jsi::Value {
126
144
  if (!arguments[0].isString()) throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
127
-
145
+
128
146
  auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime));
129
147
  [instance removeValueForKey:keyName];
130
148
  return jsi::Value::undefined();
@@ -5,20 +5,15 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.MMKV = void 0;
7
7
 
8
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
8
+ var _reactNative = require("react-native");
9
9
 
10
- /**
11
- * Used for configuration of a single MMKV instance.
12
- */
13
-
14
- /**
15
- * Represents a single MMKV instance.
16
- */
17
- // global func declaration for JSI functions
10
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
18
11
 
12
+ const onValueChangedListeners = new Map();
19
13
  /**
20
14
  * A single MMKV instance.
21
15
  */
16
+
22
17
  class MMKV {
23
18
  /**
24
19
  * Creates a new MMKV instance with the given Configuration.
@@ -31,14 +26,25 @@ class MMKV {
31
26
 
32
27
  _defineProperty(this, "functionCache", void 0);
33
28
 
29
+ _defineProperty(this, "id", void 0);
30
+
34
31
  if (global.mmkvCreateNewInstance == null) {
35
32
  throw new Error('Failed to create a new MMKV instance, the native initializer function does not exist. Is the native MMKV library correctly installed? Make sure to disable any remote debugger (e.g. Chrome) to use JSI!');
36
33
  }
37
34
 
35
+ this.id = configuration.id;
38
36
  this.nativeInstance = global.mmkvCreateNewInstance(configuration);
39
37
  this.functionCache = {};
40
38
  }
41
39
 
40
+ get onValueChangedListeners() {
41
+ if (!onValueChangedListeners.has(this.id)) {
42
+ onValueChangedListeners.set(this.id, []);
43
+ }
44
+
45
+ return onValueChangedListeners.get(this.id);
46
+ }
47
+
42
48
  getFunctionFromCache(functionName) {
43
49
  if (this.functionCache[functionName] == null) {
44
50
  this.functionCache[functionName] = this.nativeInstance[functionName];
@@ -47,7 +53,21 @@ class MMKV {
47
53
  return this.functionCache[functionName];
48
54
  }
49
55
 
56
+ onValuesAboutToChange(keys) {
57
+ if (this.onValueChangedListeners.length === 0) return;
58
+ setImmediate(() => {
59
+ (0, _reactNative.unstable_batchedUpdates)(() => {
60
+ for (const key of keys) {
61
+ for (const listener of this.onValueChangedListeners) {
62
+ listener(key);
63
+ }
64
+ }
65
+ });
66
+ });
67
+ }
68
+
50
69
  set(key, value) {
70
+ this.onValuesAboutToChange([key]);
51
71
  const func = this.getFunctionFromCache('set');
52
72
  return func(key, value);
53
73
  }
@@ -67,7 +87,13 @@ class MMKV {
67
87
  return func(key);
68
88
  }
69
89
 
90
+ contains(key) {
91
+ const func = this.getFunctionFromCache('contains');
92
+ return func(key);
93
+ }
94
+
70
95
  delete(key) {
96
+ this.onValuesAboutToChange([key]);
71
97
  const func = this.getFunctionFromCache('delete');
72
98
  return func(key);
73
99
  }
@@ -78,10 +104,25 @@ class MMKV {
78
104
  }
79
105
 
80
106
  clearAll() {
107
+ const keys = this.getAllKeys();
108
+ this.onValuesAboutToChange(keys);
81
109
  const func = this.getFunctionFromCache('clearAll');
82
110
  return func();
83
111
  }
84
112
 
113
+ addOnValueChangedListener(onValueChanged) {
114
+ this.onValueChangedListeners.push(onValueChanged);
115
+ return {
116
+ remove: () => {
117
+ const index = this.onValueChangedListeners.indexOf(onValueChanged);
118
+
119
+ if (index !== -1) {
120
+ this.onValueChangedListeners.splice(index, 1);
121
+ }
122
+ }
123
+ };
124
+ }
125
+
85
126
  }
86
127
 
87
128
  exports.MMKV = MMKV;
@@ -1 +1 @@
1
- {"version":3,"sources":["MMKV.ts"],"names":["MMKV","constructor","configuration","id","global","mmkvCreateNewInstance","Error","nativeInstance","functionCache","getFunctionFromCache","functionName","set","key","value","func","getBoolean","getString","getNumber","delete","getAllKeys","clearAll"],"mappings":";;;;;;;;;AAAA;AACA;AACA;;AAkCA;AACA;AACA;AAwCA;;AAOA;AACA;AACA;AACO,MAAMA,IAAN,CAAoC;AAIzC;AACF;AACA;AACA;AACEC,EAAAA,WAAW,CAACC,aAAgC,GAAG;AAAEC,IAAAA,EAAE,EAAE;AAAN,GAApC,EAA4D;AAAA;;AAAA;;AACrE,QAAIC,MAAM,CAACC,qBAAP,IAAgC,IAApC,EAA0C;AACxC,YAAM,IAAIC,KAAJ,CACJ,0MADI,CAAN;AAGD;;AACD,SAAKC,cAAL,GAAsBH,MAAM,CAACC,qBAAP,CAA6BH,aAA7B,CAAtB;AACA,SAAKM,aAAL,GAAqB,EAArB;AACD;;AAEOC,EAAAA,oBAAoB,CAC1BC,YAD0B,EAER;AAClB,QAAI,KAAKF,aAAL,CAAmBE,YAAnB,KAAoC,IAAxC,EAA8C;AAC5C,WAAKF,aAAL,CAAmBE,YAAnB,IAAmC,KAAKH,cAAL,CAAoBG,YAApB,CAAnC;AACD;;AACD,WAAO,KAAKF,aAAL,CAAmBE,YAAnB,CAAP;AACD;;AAEDC,EAAAA,GAAG,CAACC,GAAD,EAAcC,KAAd,EAAsD;AACvD,UAAMC,IAAI,GAAG,KAAKL,oBAAL,CAA0B,KAA1B,CAAb;AACA,WAAOK,IAAI,CAACF,GAAD,EAAMC,KAAN,CAAX;AACD;;AACDE,EAAAA,UAAU,CAACH,GAAD,EAAuB;AAC/B,UAAME,IAAI,GAAG,KAAKL,oBAAL,CAA0B,YAA1B,CAAb;AACA,WAAOK,IAAI,CAACF,GAAD,CAAX;AACD;;AACDI,EAAAA,SAAS,CAACJ,GAAD,EAAkC;AACzC,UAAME,IAAI,GAAG,KAAKL,oBAAL,CAA0B,WAA1B,CAAb;AACA,WAAOK,IAAI,CAACF,GAAD,CAAX;AACD;;AACDK,EAAAA,SAAS,CAACL,GAAD,EAAsB;AAC7B,UAAME,IAAI,GAAG,KAAKL,oBAAL,CAA0B,WAA1B,CAAb;AACA,WAAOK,IAAI,CAACF,GAAD,CAAX;AACD;;AACDM,EAAAA,MAAM,CAACN,GAAD,EAAoB;AACxB,UAAME,IAAI,GAAG,KAAKL,oBAAL,CAA0B,QAA1B,CAAb;AACA,WAAOK,IAAI,CAACF,GAAD,CAAX;AACD;;AACDO,EAAAA,UAAU,GAAa;AACrB,UAAML,IAAI,GAAG,KAAKL,oBAAL,CAA0B,YAA1B,CAAb;AACA,WAAOK,IAAI,EAAX;AACD;;AACDM,EAAAA,QAAQ,GAAS;AACf,UAAMN,IAAI,GAAG,KAAKL,oBAAL,CAA0B,UAA1B,CAAb;AACA,WAAOK,IAAI,EAAX;AACD;;AAtDwC","sourcesContent":["/**\n * Used for configuration of a single MMKV instance.\n */\nexport interface MMKVConfiguration {\n /**\n * The MMKV instance's ID. If you want to use multiple instances, make sure to use different IDs!\n *\n * @example\n * ```ts\n * const userStorage = new MMKV({ id: `user-${userId}-storage` })\n * const globalStorage = new MMKV({ id: 'global-app-storage' })\n * ```\n *\n * @default 'mmkv.default'\n */\n id: string;\n /**\n * The MMKV instance's root path. By default, MMKV stores file inside `$(Documents)/mmkv/`. You can customize MMKV's root directory on MMKV initialization:\n *\n * @example\n * ```ts\n * const temporaryStorage = new MMKV({ path: '/tmp/' })\n * ```\n */\n path?: string;\n /**\n * The MMKV instance's encryption/decryption key. By default, MMKV stores all key-values in plain text on file, relying on iOS's sandbox to make sure the file is encrypted. Should you worry about information leaking, you can choose to encrypt MMKV.\n *\n * @example\n * ```ts\n * const secureStorage = new MMKV({ encryptionKey: 'my-encryption-key!' })\n * ```\n */\n encryptionKey?: string;\n}\n\n/**\n * Represents a single MMKV instance.\n */\nexport interface MMKVInterface {\n /**\n * Set a value for the given `key`.\n */\n set: (key: string, value: boolean | string | number) => void;\n /**\n * Get a boolean value for the given `key`.\n *\n * @default false\n */\n getBoolean: (key: string) => boolean;\n /**\n * Get a string value for the given `key`.\n *\n * @default undefined\n */\n getString: (key: string) => string | undefined;\n /**\n * Get a number value for the given `key`.\n *\n * @default 0\n */\n getNumber: (key: string) => number;\n /**\n * Delete the given `key`.\n */\n delete: (key: string) => void;\n /**\n * Get all keys.\n *\n * @default []\n */\n getAllKeys: () => string[];\n /**\n * Delete all keys.\n */\n clearAll: () => void;\n}\n\n// global func declaration for JSI functions\ndeclare global {\n function mmkvCreateNewInstance(\n configuration: MMKVConfiguration\n ): MMKVInterface;\n}\n\n/**\n * A single MMKV instance.\n */\nexport class MMKV implements MMKVInterface {\n private nativeInstance: MMKVInterface;\n private functionCache: Partial<MMKVInterface>;\n\n /**\n * Creates a new MMKV instance with the given Configuration.\n * If no custom `id` is supplied, `'default'` will be used.\n */\n constructor(configuration: MMKVConfiguration = { id: 'mmkv.default' }) {\n if (global.mmkvCreateNewInstance == null) {\n throw new Error(\n 'Failed to create a new MMKV instance, the native initializer function does not exist. Is the native MMKV library correctly installed? Make sure to disable any remote debugger (e.g. Chrome) to use JSI!'\n );\n }\n this.nativeInstance = global.mmkvCreateNewInstance(configuration);\n this.functionCache = {};\n }\n\n private getFunctionFromCache<T extends keyof MMKVInterface>(\n functionName: T\n ): MMKVInterface[T] {\n if (this.functionCache[functionName] == null) {\n this.functionCache[functionName] = this.nativeInstance[functionName];\n }\n return this.functionCache[functionName] as MMKVInterface[T];\n }\n\n set(key: string, value: boolean | string | number): void {\n const func = this.getFunctionFromCache('set');\n return func(key, value);\n }\n getBoolean(key: string): boolean {\n const func = this.getFunctionFromCache('getBoolean');\n return func(key);\n }\n getString(key: string): string | undefined {\n const func = this.getFunctionFromCache('getString');\n return func(key);\n }\n getNumber(key: string): number {\n const func = this.getFunctionFromCache('getNumber');\n return func(key);\n }\n delete(key: string): void {\n const func = this.getFunctionFromCache('delete');\n return func(key);\n }\n getAllKeys(): string[] {\n const func = this.getFunctionFromCache('getAllKeys');\n return func();\n }\n clearAll(): void {\n const func = this.getFunctionFromCache('clearAll');\n return func();\n }\n}\n"]}
1
+ {"version":3,"sources":["MMKV.ts"],"names":["onValueChangedListeners","Map","MMKV","constructor","configuration","id","global","mmkvCreateNewInstance","Error","nativeInstance","functionCache","has","set","get","getFunctionFromCache","functionName","onValuesAboutToChange","keys","length","setImmediate","key","listener","value","func","getBoolean","getString","getNumber","contains","delete","getAllKeys","clearAll","addOnValueChangedListener","onValueChanged","push","remove","index","indexOf","splice"],"mappings":"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","sourcesContent":["import { unstable_batchedUpdates } from 'react-native';\n\ninterface Listener {\n remove: () => void;\n}\n\n/**\n * Used for configuration of a single MMKV instance.\n */\nexport interface MMKVConfiguration {\n /**\n * The MMKV instance's ID. If you want to use multiple instances, make sure to use different IDs!\n *\n * @example\n * ```ts\n * const userStorage = new MMKV({ id: `user-${userId}-storage` })\n * const globalStorage = new MMKV({ id: 'global-app-storage' })\n * ```\n *\n * @default 'mmkv.default'\n */\n id: string;\n /**\n * The MMKV instance's root path. By default, MMKV stores file inside `$(Documents)/mmkv/`. You can customize MMKV's root directory on MMKV initialization:\n *\n * @example\n * ```ts\n * const temporaryStorage = new MMKV({ path: '/tmp/' })\n * ```\n */\n path?: string;\n /**\n * The MMKV instance's encryption/decryption key. By default, MMKV stores all key-values in plain text on file, relying on iOS's sandbox to make sure the file is encrypted. Should you worry about information leaking, you can choose to encrypt MMKV.\n *\n * @example\n * ```ts\n * const secureStorage = new MMKV({ encryptionKey: 'my-encryption-key!' })\n * ```\n */\n encryptionKey?: string;\n}\n\n/**\n * Represents a single MMKV instance.\n */\nexport interface MMKVInterface {\n /**\n * Set a value for the given `key`.\n */\n set: (key: string, value: boolean | string | number) => void;\n /**\n * Get a boolean value for the given `key`.\n *\n * @default false\n */\n getBoolean: (key: string) => boolean;\n /**\n * Get a string value for the given `key`.\n *\n * @default undefined\n */\n getString: (key: string) => string | undefined;\n /**\n * Get a number value for the given `key`.\n *\n * @default 0\n */\n getNumber: (key: string) => number;\n /**\n * Checks whether the given `key` is being stored in this MMKV instance.\n */\n contains: (key: string) => boolean;\n /**\n * Delete the given `key`.\n */\n delete: (key: string) => void;\n /**\n * Get all keys.\n *\n * @default []\n */\n getAllKeys: () => string[];\n /**\n * Delete all keys.\n */\n clearAll: () => void;\n /**\n * Adds a value changed listener.\n */\n addOnValueChangedListener: (\n onValueChanged: (key: string) => void\n ) => Listener;\n}\n\n// global func declaration for JSI functions\ndeclare global {\n function mmkvCreateNewInstance(\n configuration: MMKVConfiguration\n ): MMKVInterface;\n}\n\nconst onValueChangedListeners = new Map<string, ((key: string) => void)[]>();\n\n/**\n * A single MMKV instance.\n */\nexport class MMKV implements MMKVInterface {\n private nativeInstance: MMKVInterface;\n private functionCache: Partial<MMKVInterface>;\n private id: string;\n\n /**\n * Creates a new MMKV instance with the given Configuration.\n * If no custom `id` is supplied, `'default'` will be used.\n */\n constructor(configuration: MMKVConfiguration = { id: 'mmkv.default' }) {\n if (global.mmkvCreateNewInstance == null) {\n throw new Error(\n 'Failed to create a new MMKV instance, the native initializer function does not exist. Is the native MMKV library correctly installed? Make sure to disable any remote debugger (e.g. Chrome) to use JSI!'\n );\n }\n this.id = configuration.id;\n this.nativeInstance = global.mmkvCreateNewInstance(configuration);\n this.functionCache = {};\n }\n\n private get onValueChangedListeners() {\n if (!onValueChangedListeners.has(this.id)) {\n onValueChangedListeners.set(this.id, []);\n }\n return onValueChangedListeners.get(this.id)!;\n }\n\n private getFunctionFromCache<T extends keyof MMKVInterface>(\n functionName: T\n ): MMKVInterface[T] {\n if (this.functionCache[functionName] == null) {\n this.functionCache[functionName] = this.nativeInstance[functionName];\n }\n return this.functionCache[functionName] as MMKVInterface[T];\n }\n\n private onValuesAboutToChange(keys: string[]) {\n if (this.onValueChangedListeners.length === 0) return;\n\n setImmediate(() => {\n unstable_batchedUpdates(() => {\n for (const key of keys) {\n for (const listener of this.onValueChangedListeners) {\n listener(key);\n }\n }\n });\n });\n }\n\n set(key: string, value: boolean | string | number): void {\n this.onValuesAboutToChange([key]);\n\n const func = this.getFunctionFromCache('set');\n return func(key, value);\n }\n getBoolean(key: string): boolean {\n const func = this.getFunctionFromCache('getBoolean');\n return func(key);\n }\n getString(key: string): string | undefined {\n const func = this.getFunctionFromCache('getString');\n return func(key);\n }\n getNumber(key: string): number {\n const func = this.getFunctionFromCache('getNumber');\n return func(key);\n }\n contains(key: string): boolean {\n const func = this.getFunctionFromCache('contains');\n return func(key);\n }\n delete(key: string): void {\n this.onValuesAboutToChange([key]);\n\n const func = this.getFunctionFromCache('delete');\n return func(key);\n }\n getAllKeys(): string[] {\n const func = this.getFunctionFromCache('getAllKeys');\n return func();\n }\n clearAll(): void {\n const keys = this.getAllKeys();\n this.onValuesAboutToChange(keys);\n\n const func = this.getFunctionFromCache('clearAll');\n return func();\n }\n\n addOnValueChangedListener(onValueChanged: (key: string) => void): Listener {\n this.onValueChangedListeners.push(onValueChanged);\n\n return {\n remove: () => {\n const index = this.onValueChangedListeners.indexOf(onValueChanged);\n if (index !== -1) {\n this.onValueChangedListeners.splice(index, 1);\n }\n },\n };\n }\n}\n"]}
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useMMKV = useMMKV;
7
+ exports.useMMKVNumber = exports.useMMKVBoolean = void 0;
8
+ exports.useMMKVObject = useMMKVObject;
9
+ exports.useMMKVString = void 0;
10
+
11
+ var _react = require("react");
12
+
13
+ var _MMKV = require("./MMKV");
14
+
15
+ function isConfigurationEqual(left, right) {
16
+ return left.encryptionKey === right.encryptionKey && left.id === right.id && left.path === right.path;
17
+ }
18
+
19
+ let defaultInstance = null;
20
+
21
+ function getDefaultInstance() {
22
+ if (defaultInstance == null) {
23
+ defaultInstance = new _MMKV.MMKV();
24
+ }
25
+
26
+ return defaultInstance;
27
+ }
28
+
29
+ function useMMKV(configuration) {
30
+ const instance = (0, _react.useRef)();
31
+ const lastConfiguration = (0, _react.useRef)(configuration);
32
+
33
+ if (!isConfigurationEqual(lastConfiguration.current, configuration)) {
34
+ instance.current = new _MMKV.MMKV(configuration);
35
+ } // @ts-expect-error it's not null, I promise.
36
+
37
+
38
+ return instance;
39
+ }
40
+
41
+ function createMMKVHook(getter) {
42
+ return (key, instance) => {
43
+ const mmkv = instance !== null && instance !== void 0 ? instance : getDefaultInstance();
44
+ const [value, setValue] = (0, _react.useState)(() => getter(mmkv, key));
45
+ const set = (0, _react.useCallback)(v => {
46
+ const newValue = typeof v === 'function' ? v(value) : v;
47
+
48
+ switch (typeof newValue) {
49
+ case 'number':
50
+ case 'string':
51
+ case 'boolean':
52
+ mmkv.set(key, newValue);
53
+ break;
54
+
55
+ case 'undefined':
56
+ mmkv.delete(key);
57
+ break;
58
+
59
+ default:
60
+ throw new Error(`MMKV: Type ${typeof newValue} is not supported!`);
61
+ }
62
+ }, [key, mmkv, value]);
63
+ (0, _react.useEffect)(() => {
64
+ const listener = mmkv.addOnValueChangedListener(changedKey => {
65
+ if (changedKey === key) {
66
+ setValue(getter(mmkv, key));
67
+ }
68
+ });
69
+ return () => listener.remove();
70
+ }, [key, mmkv]);
71
+ return (0, _react.useMemo)(() => [value, set], [value, set]);
72
+ };
73
+ }
74
+ /**
75
+ * Use the string value of the given `key` from the given MMKV storage instance.
76
+ *
77
+ * If no instance is provided, a shared default instance will be used.
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * const [username, setUsername] = useMMKVString("user.name")
82
+ * ```
83
+ */
84
+
85
+
86
+ const useMMKVString = createMMKVHook((instance, key) => instance.getString(key));
87
+ /**
88
+ * Use the number value of the given `key` from the given MMKV storage instance.
89
+ *
90
+ * If no instance is provided, a shared default instance will be used.
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * const [age, setAge] = useMMKVNumber("user.age")
95
+ * ```
96
+ */
97
+
98
+ exports.useMMKVString = useMMKVString;
99
+ const useMMKVNumber = createMMKVHook((instance, key) => instance.getNumber(key));
100
+ /**
101
+ * Use the boolean value of the given `key` from the given MMKV storage instance.
102
+ *
103
+ * If no instance is provided, a shared default instance will be used.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * const [isPremiumAccount, setIsPremiumAccount] = useMMKVBoolean("user.isPremium")
108
+ * ```
109
+ */
110
+
111
+ exports.useMMKVNumber = useMMKVNumber;
112
+ const useMMKVBoolean = createMMKVHook((instance, key) => instance.getBoolean(key));
113
+ /**
114
+ * Use an object value of the given `key` from the given MMKV storage instance.
115
+ *
116
+ * If no instance is provided, a shared default instance will be used.
117
+ *
118
+ * The object will be serialized using `JSON`.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * const [user, setUser] = useMMKVObject<User>("user")
123
+ * ```
124
+ */
125
+
126
+ exports.useMMKVBoolean = useMMKVBoolean;
127
+
128
+ function useMMKVObject(key, instance) {
129
+ const [string, setString] = useMMKVString(key, instance);
130
+ const value = (0, _react.useMemo)(() => {
131
+ if (string == null) return undefined;
132
+ return JSON.parse(string);
133
+ }, [string]);
134
+ const setValue = (0, _react.useCallback)(v => {
135
+ setString(JSON.stringify(v));
136
+ }, [setString]);
137
+ return [value, setValue];
138
+ }
139
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["hooks.ts"],"names":["isConfigurationEqual","left","right","encryptionKey","id","path","defaultInstance","getDefaultInstance","MMKV","useMMKV","configuration","instance","lastConfiguration","current","createMMKVHook","getter","key","mmkv","value","setValue","set","v","newValue","delete","Error","listener","addOnValueChangedListener","changedKey","remove","useMMKVString","getString","useMMKVNumber","getNumber","useMMKVBoolean","getBoolean","useMMKVObject","string","setString","undefined","JSON","parse","stringify"],"mappings":"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","sourcesContent":["import React, {\n useRef,\n useState,\n useMemo,\n useCallback,\n useEffect,\n} from 'react';\nimport { MMKV, MMKVConfiguration, MMKVInterface } from './MMKV';\n\nfunction isConfigurationEqual(\n left: MMKVConfiguration,\n right: MMKVConfiguration\n): boolean {\n return (\n left.encryptionKey === right.encryptionKey &&\n left.id === right.id &&\n left.path === right.path\n );\n}\n\nlet defaultInstance: MMKVInterface | null = null;\nfunction getDefaultInstance(): MMKVInterface {\n if (defaultInstance == null) {\n defaultInstance = new MMKV();\n }\n return defaultInstance;\n}\n\nexport function useMMKV(\n configuration: MMKVConfiguration\n): React.RefObject<MMKVInterface> {\n const instance = useRef<MMKVInterface>();\n\n const lastConfiguration = useRef<MMKVConfiguration>(configuration);\n if (!isConfigurationEqual(lastConfiguration.current, configuration)) {\n instance.current = new MMKV(configuration);\n }\n\n // @ts-expect-error it's not null, I promise.\n return instance;\n}\n\nfunction createMMKVHook<\n T extends boolean | number | (string | undefined),\n TSet extends T | undefined,\n TSetAction extends TSet | ((current: T) => TSet)\n>(getter: (instance: MMKVInterface, key: string) => T) {\n return (\n key: string,\n instance?: MMKVInterface\n ): [value: T, setValue: (value: TSetAction) => void] => {\n const mmkv = instance ?? getDefaultInstance();\n const [value, setValue] = useState(() => getter(mmkv, key));\n\n const set = useCallback(\n (v: TSetAction) => {\n const newValue = typeof v === 'function' ? v(value) : v;\n switch (typeof newValue) {\n case 'number':\n case 'string':\n case 'boolean':\n mmkv.set(key, newValue);\n break;\n case 'undefined':\n mmkv.delete(key);\n break;\n default:\n throw new Error(`MMKV: Type ${typeof newValue} is not supported!`);\n }\n },\n [key, mmkv, value]\n );\n\n useEffect(() => {\n const listener = mmkv.addOnValueChangedListener((changedKey) => {\n if (changedKey === key) {\n setValue(getter(mmkv, key));\n }\n });\n return () => listener.remove();\n }, [key, mmkv]);\n\n return useMemo(() => [value, set], [value, set]);\n };\n}\n\n/**\n * Use the string value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [username, setUsername] = useMMKVString(\"user.name\")\n * ```\n */\nexport const useMMKVString = createMMKVHook((instance, key) =>\n instance.getString(key)\n);\n\n/**\n * Use the number value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [age, setAge] = useMMKVNumber(\"user.age\")\n * ```\n */\nexport const useMMKVNumber = createMMKVHook((instance, key) =>\n instance.getNumber(key)\n);\n/**\n * Use the boolean value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [isPremiumAccount, setIsPremiumAccount] = useMMKVBoolean(\"user.isPremium\")\n * ```\n */\nexport const useMMKVBoolean = createMMKVHook((instance, key) =>\n instance.getBoolean(key)\n);\n/**\n * Use an object value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * The object will be serialized using `JSON`.\n *\n * @example\n * ```ts\n * const [user, setUser] = useMMKVObject<User>(\"user\")\n * ```\n */\nexport function useMMKVObject<T>(\n key: string,\n instance?: MMKVInterface\n): [value: T | undefined, setValue: (value: T) => void] {\n const [string, setString] = useMMKVString(key, instance);\n\n const value = useMemo(() => {\n if (string == null) return undefined;\n return JSON.parse(string) as T;\n }, [string]);\n const setValue = useCallback(\n (v: T) => {\n setString(JSON.stringify(v));\n },\n [setString]\n );\n\n return [value, setValue];\n}\n"]}
@@ -16,4 +16,17 @@ Object.keys(_MMKV).forEach(function (key) {
16
16
  }
17
17
  });
18
18
  });
19
+
20
+ var _hooks = require("./hooks");
21
+
22
+ Object.keys(_hooks).forEach(function (key) {
23
+ if (key === "default" || key === "__esModule") return;
24
+ if (key in exports && exports[key] === _hooks[key]) return;
25
+ Object.defineProperty(exports, key, {
26
+ enumerable: true,
27
+ get: function () {
28
+ return _hooks[key];
29
+ }
30
+ });
31
+ });
19
32
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["index.ts"],"names":[],"mappings":";;;;;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA","sourcesContent":["export * from './MMKV';\n"]}
1
+ {"version":3,"sources":["index.ts"],"names":[],"mappings":";;;;;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AACA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA","sourcesContent":["export * from './MMKV';\nexport * from './hooks';\n"]}
@@ -1,17 +1,11 @@
1
1
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2
2
 
3
- /**
4
- * Used for configuration of a single MMKV instance.
5
- */
6
-
7
- /**
8
- * Represents a single MMKV instance.
9
- */
10
- // global func declaration for JSI functions
11
-
3
+ import { unstable_batchedUpdates } from 'react-native';
4
+ const onValueChangedListeners = new Map();
12
5
  /**
13
6
  * A single MMKV instance.
14
7
  */
8
+
15
9
  export class MMKV {
16
10
  /**
17
11
  * Creates a new MMKV instance with the given Configuration.
@@ -24,14 +18,25 @@ export class MMKV {
24
18
 
25
19
  _defineProperty(this, "functionCache", void 0);
26
20
 
21
+ _defineProperty(this, "id", void 0);
22
+
27
23
  if (global.mmkvCreateNewInstance == null) {
28
24
  throw new Error('Failed to create a new MMKV instance, the native initializer function does not exist. Is the native MMKV library correctly installed? Make sure to disable any remote debugger (e.g. Chrome) to use JSI!');
29
25
  }
30
26
 
27
+ this.id = configuration.id;
31
28
  this.nativeInstance = global.mmkvCreateNewInstance(configuration);
32
29
  this.functionCache = {};
33
30
  }
34
31
 
32
+ get onValueChangedListeners() {
33
+ if (!onValueChangedListeners.has(this.id)) {
34
+ onValueChangedListeners.set(this.id, []);
35
+ }
36
+
37
+ return onValueChangedListeners.get(this.id);
38
+ }
39
+
35
40
  getFunctionFromCache(functionName) {
36
41
  if (this.functionCache[functionName] == null) {
37
42
  this.functionCache[functionName] = this.nativeInstance[functionName];
@@ -40,7 +45,21 @@ export class MMKV {
40
45
  return this.functionCache[functionName];
41
46
  }
42
47
 
48
+ onValuesAboutToChange(keys) {
49
+ if (this.onValueChangedListeners.length === 0) return;
50
+ setImmediate(() => {
51
+ unstable_batchedUpdates(() => {
52
+ for (const key of keys) {
53
+ for (const listener of this.onValueChangedListeners) {
54
+ listener(key);
55
+ }
56
+ }
57
+ });
58
+ });
59
+ }
60
+
43
61
  set(key, value) {
62
+ this.onValuesAboutToChange([key]);
44
63
  const func = this.getFunctionFromCache('set');
45
64
  return func(key, value);
46
65
  }
@@ -60,7 +79,13 @@ export class MMKV {
60
79
  return func(key);
61
80
  }
62
81
 
82
+ contains(key) {
83
+ const func = this.getFunctionFromCache('contains');
84
+ return func(key);
85
+ }
86
+
63
87
  delete(key) {
88
+ this.onValuesAboutToChange([key]);
64
89
  const func = this.getFunctionFromCache('delete');
65
90
  return func(key);
66
91
  }
@@ -71,9 +96,24 @@ export class MMKV {
71
96
  }
72
97
 
73
98
  clearAll() {
99
+ const keys = this.getAllKeys();
100
+ this.onValuesAboutToChange(keys);
74
101
  const func = this.getFunctionFromCache('clearAll');
75
102
  return func();
76
103
  }
77
104
 
105
+ addOnValueChangedListener(onValueChanged) {
106
+ this.onValueChangedListeners.push(onValueChanged);
107
+ return {
108
+ remove: () => {
109
+ const index = this.onValueChangedListeners.indexOf(onValueChanged);
110
+
111
+ if (index !== -1) {
112
+ this.onValueChangedListeners.splice(index, 1);
113
+ }
114
+ }
115
+ };
116
+ }
117
+
78
118
  }
79
119
  //# sourceMappingURL=MMKV.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["MMKV.ts"],"names":["MMKV","constructor","configuration","id","global","mmkvCreateNewInstance","Error","nativeInstance","functionCache","getFunctionFromCache","functionName","set","key","value","func","getBoolean","getString","getNumber","delete","getAllKeys","clearAll"],"mappings":";;AAAA;AACA;AACA;;AAkCA;AACA;AACA;AAwCA;;AAOA;AACA;AACA;AACA,OAAO,MAAMA,IAAN,CAAoC;AAIzC;AACF;AACA;AACA;AACEC,EAAAA,WAAW,CAACC,aAAgC,GAAG;AAAEC,IAAAA,EAAE,EAAE;AAAN,GAApC,EAA4D;AAAA;;AAAA;;AACrE,QAAIC,MAAM,CAACC,qBAAP,IAAgC,IAApC,EAA0C;AACxC,YAAM,IAAIC,KAAJ,CACJ,0MADI,CAAN;AAGD;;AACD,SAAKC,cAAL,GAAsBH,MAAM,CAACC,qBAAP,CAA6BH,aAA7B,CAAtB;AACA,SAAKM,aAAL,GAAqB,EAArB;AACD;;AAEOC,EAAAA,oBAAoB,CAC1BC,YAD0B,EAER;AAClB,QAAI,KAAKF,aAAL,CAAmBE,YAAnB,KAAoC,IAAxC,EAA8C;AAC5C,WAAKF,aAAL,CAAmBE,YAAnB,IAAmC,KAAKH,cAAL,CAAoBG,YAApB,CAAnC;AACD;;AACD,WAAO,KAAKF,aAAL,CAAmBE,YAAnB,CAAP;AACD;;AAEDC,EAAAA,GAAG,CAACC,GAAD,EAAcC,KAAd,EAAsD;AACvD,UAAMC,IAAI,GAAG,KAAKL,oBAAL,CAA0B,KAA1B,CAAb;AACA,WAAOK,IAAI,CAACF,GAAD,EAAMC,KAAN,CAAX;AACD;;AACDE,EAAAA,UAAU,CAACH,GAAD,EAAuB;AAC/B,UAAME,IAAI,GAAG,KAAKL,oBAAL,CAA0B,YAA1B,CAAb;AACA,WAAOK,IAAI,CAACF,GAAD,CAAX;AACD;;AACDI,EAAAA,SAAS,CAACJ,GAAD,EAAkC;AACzC,UAAME,IAAI,GAAG,KAAKL,oBAAL,CAA0B,WAA1B,CAAb;AACA,WAAOK,IAAI,CAACF,GAAD,CAAX;AACD;;AACDK,EAAAA,SAAS,CAACL,GAAD,EAAsB;AAC7B,UAAME,IAAI,GAAG,KAAKL,oBAAL,CAA0B,WAA1B,CAAb;AACA,WAAOK,IAAI,CAACF,GAAD,CAAX;AACD;;AACDM,EAAAA,MAAM,CAACN,GAAD,EAAoB;AACxB,UAAME,IAAI,GAAG,KAAKL,oBAAL,CAA0B,QAA1B,CAAb;AACA,WAAOK,IAAI,CAACF,GAAD,CAAX;AACD;;AACDO,EAAAA,UAAU,GAAa;AACrB,UAAML,IAAI,GAAG,KAAKL,oBAAL,CAA0B,YAA1B,CAAb;AACA,WAAOK,IAAI,EAAX;AACD;;AACDM,EAAAA,QAAQ,GAAS;AACf,UAAMN,IAAI,GAAG,KAAKL,oBAAL,CAA0B,UAA1B,CAAb;AACA,WAAOK,IAAI,EAAX;AACD;;AAtDwC","sourcesContent":["/**\n * Used for configuration of a single MMKV instance.\n */\nexport interface MMKVConfiguration {\n /**\n * The MMKV instance's ID. If you want to use multiple instances, make sure to use different IDs!\n *\n * @example\n * ```ts\n * const userStorage = new MMKV({ id: `user-${userId}-storage` })\n * const globalStorage = new MMKV({ id: 'global-app-storage' })\n * ```\n *\n * @default 'mmkv.default'\n */\n id: string;\n /**\n * The MMKV instance's root path. By default, MMKV stores file inside `$(Documents)/mmkv/`. You can customize MMKV's root directory on MMKV initialization:\n *\n * @example\n * ```ts\n * const temporaryStorage = new MMKV({ path: '/tmp/' })\n * ```\n */\n path?: string;\n /**\n * The MMKV instance's encryption/decryption key. By default, MMKV stores all key-values in plain text on file, relying on iOS's sandbox to make sure the file is encrypted. Should you worry about information leaking, you can choose to encrypt MMKV.\n *\n * @example\n * ```ts\n * const secureStorage = new MMKV({ encryptionKey: 'my-encryption-key!' })\n * ```\n */\n encryptionKey?: string;\n}\n\n/**\n * Represents a single MMKV instance.\n */\nexport interface MMKVInterface {\n /**\n * Set a value for the given `key`.\n */\n set: (key: string, value: boolean | string | number) => void;\n /**\n * Get a boolean value for the given `key`.\n *\n * @default false\n */\n getBoolean: (key: string) => boolean;\n /**\n * Get a string value for the given `key`.\n *\n * @default undefined\n */\n getString: (key: string) => string | undefined;\n /**\n * Get a number value for the given `key`.\n *\n * @default 0\n */\n getNumber: (key: string) => number;\n /**\n * Delete the given `key`.\n */\n delete: (key: string) => void;\n /**\n * Get all keys.\n *\n * @default []\n */\n getAllKeys: () => string[];\n /**\n * Delete all keys.\n */\n clearAll: () => void;\n}\n\n// global func declaration for JSI functions\ndeclare global {\n function mmkvCreateNewInstance(\n configuration: MMKVConfiguration\n ): MMKVInterface;\n}\n\n/**\n * A single MMKV instance.\n */\nexport class MMKV implements MMKVInterface {\n private nativeInstance: MMKVInterface;\n private functionCache: Partial<MMKVInterface>;\n\n /**\n * Creates a new MMKV instance with the given Configuration.\n * If no custom `id` is supplied, `'default'` will be used.\n */\n constructor(configuration: MMKVConfiguration = { id: 'mmkv.default' }) {\n if (global.mmkvCreateNewInstance == null) {\n throw new Error(\n 'Failed to create a new MMKV instance, the native initializer function does not exist. Is the native MMKV library correctly installed? Make sure to disable any remote debugger (e.g. Chrome) to use JSI!'\n );\n }\n this.nativeInstance = global.mmkvCreateNewInstance(configuration);\n this.functionCache = {};\n }\n\n private getFunctionFromCache<T extends keyof MMKVInterface>(\n functionName: T\n ): MMKVInterface[T] {\n if (this.functionCache[functionName] == null) {\n this.functionCache[functionName] = this.nativeInstance[functionName];\n }\n return this.functionCache[functionName] as MMKVInterface[T];\n }\n\n set(key: string, value: boolean | string | number): void {\n const func = this.getFunctionFromCache('set');\n return func(key, value);\n }\n getBoolean(key: string): boolean {\n const func = this.getFunctionFromCache('getBoolean');\n return func(key);\n }\n getString(key: string): string | undefined {\n const func = this.getFunctionFromCache('getString');\n return func(key);\n }\n getNumber(key: string): number {\n const func = this.getFunctionFromCache('getNumber');\n return func(key);\n }\n delete(key: string): void {\n const func = this.getFunctionFromCache('delete');\n return func(key);\n }\n getAllKeys(): string[] {\n const func = this.getFunctionFromCache('getAllKeys');\n return func();\n }\n clearAll(): void {\n const func = this.getFunctionFromCache('clearAll');\n return func();\n }\n}\n"]}
1
+ {"version":3,"sources":["MMKV.ts"],"names":["unstable_batchedUpdates","onValueChangedListeners","Map","MMKV","constructor","configuration","id","global","mmkvCreateNewInstance","Error","nativeInstance","functionCache","has","set","get","getFunctionFromCache","functionName","onValuesAboutToChange","keys","length","setImmediate","key","listener","value","func","getBoolean","getString","getNumber","contains","delete","getAllKeys","clearAll","addOnValueChangedListener","onValueChanged","push","remove","index","indexOf","splice"],"mappings":"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","sourcesContent":["import { unstable_batchedUpdates } from 'react-native';\n\ninterface Listener {\n remove: () => void;\n}\n\n/**\n * Used for configuration of a single MMKV instance.\n */\nexport interface MMKVConfiguration {\n /**\n * The MMKV instance's ID. If you want to use multiple instances, make sure to use different IDs!\n *\n * @example\n * ```ts\n * const userStorage = new MMKV({ id: `user-${userId}-storage` })\n * const globalStorage = new MMKV({ id: 'global-app-storage' })\n * ```\n *\n * @default 'mmkv.default'\n */\n id: string;\n /**\n * The MMKV instance's root path. By default, MMKV stores file inside `$(Documents)/mmkv/`. You can customize MMKV's root directory on MMKV initialization:\n *\n * @example\n * ```ts\n * const temporaryStorage = new MMKV({ path: '/tmp/' })\n * ```\n */\n path?: string;\n /**\n * The MMKV instance's encryption/decryption key. By default, MMKV stores all key-values in plain text on file, relying on iOS's sandbox to make sure the file is encrypted. Should you worry about information leaking, you can choose to encrypt MMKV.\n *\n * @example\n * ```ts\n * const secureStorage = new MMKV({ encryptionKey: 'my-encryption-key!' })\n * ```\n */\n encryptionKey?: string;\n}\n\n/**\n * Represents a single MMKV instance.\n */\nexport interface MMKVInterface {\n /**\n * Set a value for the given `key`.\n */\n set: (key: string, value: boolean | string | number) => void;\n /**\n * Get a boolean value for the given `key`.\n *\n * @default false\n */\n getBoolean: (key: string) => boolean;\n /**\n * Get a string value for the given `key`.\n *\n * @default undefined\n */\n getString: (key: string) => string | undefined;\n /**\n * Get a number value for the given `key`.\n *\n * @default 0\n */\n getNumber: (key: string) => number;\n /**\n * Checks whether the given `key` is being stored in this MMKV instance.\n */\n contains: (key: string) => boolean;\n /**\n * Delete the given `key`.\n */\n delete: (key: string) => void;\n /**\n * Get all keys.\n *\n * @default []\n */\n getAllKeys: () => string[];\n /**\n * Delete all keys.\n */\n clearAll: () => void;\n /**\n * Adds a value changed listener.\n */\n addOnValueChangedListener: (\n onValueChanged: (key: string) => void\n ) => Listener;\n}\n\n// global func declaration for JSI functions\ndeclare global {\n function mmkvCreateNewInstance(\n configuration: MMKVConfiguration\n ): MMKVInterface;\n}\n\nconst onValueChangedListeners = new Map<string, ((key: string) => void)[]>();\n\n/**\n * A single MMKV instance.\n */\nexport class MMKV implements MMKVInterface {\n private nativeInstance: MMKVInterface;\n private functionCache: Partial<MMKVInterface>;\n private id: string;\n\n /**\n * Creates a new MMKV instance with the given Configuration.\n * If no custom `id` is supplied, `'default'` will be used.\n */\n constructor(configuration: MMKVConfiguration = { id: 'mmkv.default' }) {\n if (global.mmkvCreateNewInstance == null) {\n throw new Error(\n 'Failed to create a new MMKV instance, the native initializer function does not exist. Is the native MMKV library correctly installed? Make sure to disable any remote debugger (e.g. Chrome) to use JSI!'\n );\n }\n this.id = configuration.id;\n this.nativeInstance = global.mmkvCreateNewInstance(configuration);\n this.functionCache = {};\n }\n\n private get onValueChangedListeners() {\n if (!onValueChangedListeners.has(this.id)) {\n onValueChangedListeners.set(this.id, []);\n }\n return onValueChangedListeners.get(this.id)!;\n }\n\n private getFunctionFromCache<T extends keyof MMKVInterface>(\n functionName: T\n ): MMKVInterface[T] {\n if (this.functionCache[functionName] == null) {\n this.functionCache[functionName] = this.nativeInstance[functionName];\n }\n return this.functionCache[functionName] as MMKVInterface[T];\n }\n\n private onValuesAboutToChange(keys: string[]) {\n if (this.onValueChangedListeners.length === 0) return;\n\n setImmediate(() => {\n unstable_batchedUpdates(() => {\n for (const key of keys) {\n for (const listener of this.onValueChangedListeners) {\n listener(key);\n }\n }\n });\n });\n }\n\n set(key: string, value: boolean | string | number): void {\n this.onValuesAboutToChange([key]);\n\n const func = this.getFunctionFromCache('set');\n return func(key, value);\n }\n getBoolean(key: string): boolean {\n const func = this.getFunctionFromCache('getBoolean');\n return func(key);\n }\n getString(key: string): string | undefined {\n const func = this.getFunctionFromCache('getString');\n return func(key);\n }\n getNumber(key: string): number {\n const func = this.getFunctionFromCache('getNumber');\n return func(key);\n }\n contains(key: string): boolean {\n const func = this.getFunctionFromCache('contains');\n return func(key);\n }\n delete(key: string): void {\n this.onValuesAboutToChange([key]);\n\n const func = this.getFunctionFromCache('delete');\n return func(key);\n }\n getAllKeys(): string[] {\n const func = this.getFunctionFromCache('getAllKeys');\n return func();\n }\n clearAll(): void {\n const keys = this.getAllKeys();\n this.onValuesAboutToChange(keys);\n\n const func = this.getFunctionFromCache('clearAll');\n return func();\n }\n\n addOnValueChangedListener(onValueChanged: (key: string) => void): Listener {\n this.onValueChangedListeners.push(onValueChanged);\n\n return {\n remove: () => {\n const index = this.onValueChangedListeners.indexOf(onValueChanged);\n if (index !== -1) {\n this.onValueChangedListeners.splice(index, 1);\n }\n },\n };\n }\n}\n"]}
@@ -0,0 +1,124 @@
1
+ import { useRef, useState, useMemo, useCallback, useEffect } from 'react';
2
+ import { MMKV } from './MMKV';
3
+
4
+ function isConfigurationEqual(left, right) {
5
+ return left.encryptionKey === right.encryptionKey && left.id === right.id && left.path === right.path;
6
+ }
7
+
8
+ let defaultInstance = null;
9
+
10
+ function getDefaultInstance() {
11
+ if (defaultInstance == null) {
12
+ defaultInstance = new MMKV();
13
+ }
14
+
15
+ return defaultInstance;
16
+ }
17
+
18
+ export function useMMKV(configuration) {
19
+ const instance = useRef();
20
+ const lastConfiguration = useRef(configuration);
21
+
22
+ if (!isConfigurationEqual(lastConfiguration.current, configuration)) {
23
+ instance.current = new MMKV(configuration);
24
+ } // @ts-expect-error it's not null, I promise.
25
+
26
+
27
+ return instance;
28
+ }
29
+
30
+ function createMMKVHook(getter) {
31
+ return (key, instance) => {
32
+ const mmkv = instance !== null && instance !== void 0 ? instance : getDefaultInstance();
33
+ const [value, setValue] = useState(() => getter(mmkv, key));
34
+ const set = useCallback(v => {
35
+ const newValue = typeof v === 'function' ? v(value) : v;
36
+
37
+ switch (typeof newValue) {
38
+ case 'number':
39
+ case 'string':
40
+ case 'boolean':
41
+ mmkv.set(key, newValue);
42
+ break;
43
+
44
+ case 'undefined':
45
+ mmkv.delete(key);
46
+ break;
47
+
48
+ default:
49
+ throw new Error(`MMKV: Type ${typeof newValue} is not supported!`);
50
+ }
51
+ }, [key, mmkv, value]);
52
+ useEffect(() => {
53
+ const listener = mmkv.addOnValueChangedListener(changedKey => {
54
+ if (changedKey === key) {
55
+ setValue(getter(mmkv, key));
56
+ }
57
+ });
58
+ return () => listener.remove();
59
+ }, [key, mmkv]);
60
+ return useMemo(() => [value, set], [value, set]);
61
+ };
62
+ }
63
+ /**
64
+ * Use the string value of the given `key` from the given MMKV storage instance.
65
+ *
66
+ * If no instance is provided, a shared default instance will be used.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * const [username, setUsername] = useMMKVString("user.name")
71
+ * ```
72
+ */
73
+
74
+
75
+ export const useMMKVString = createMMKVHook((instance, key) => instance.getString(key));
76
+ /**
77
+ * Use the number value of the given `key` from the given MMKV storage instance.
78
+ *
79
+ * If no instance is provided, a shared default instance will be used.
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * const [age, setAge] = useMMKVNumber("user.age")
84
+ * ```
85
+ */
86
+
87
+ export const useMMKVNumber = createMMKVHook((instance, key) => instance.getNumber(key));
88
+ /**
89
+ * Use the boolean value of the given `key` from the given MMKV storage instance.
90
+ *
91
+ * If no instance is provided, a shared default instance will be used.
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * const [isPremiumAccount, setIsPremiumAccount] = useMMKVBoolean("user.isPremium")
96
+ * ```
97
+ */
98
+
99
+ export const useMMKVBoolean = createMMKVHook((instance, key) => instance.getBoolean(key));
100
+ /**
101
+ * Use an object value of the given `key` from the given MMKV storage instance.
102
+ *
103
+ * If no instance is provided, a shared default instance will be used.
104
+ *
105
+ * The object will be serialized using `JSON`.
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * const [user, setUser] = useMMKVObject<User>("user")
110
+ * ```
111
+ */
112
+
113
+ export function useMMKVObject(key, instance) {
114
+ const [string, setString] = useMMKVString(key, instance);
115
+ const value = useMemo(() => {
116
+ if (string == null) return undefined;
117
+ return JSON.parse(string);
118
+ }, [string]);
119
+ const setValue = useCallback(v => {
120
+ setString(JSON.stringify(v));
121
+ }, [setString]);
122
+ return [value, setValue];
123
+ }
124
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["hooks.ts"],"names":["useRef","useState","useMemo","useCallback","useEffect","MMKV","isConfigurationEqual","left","right","encryptionKey","id","path","defaultInstance","getDefaultInstance","useMMKV","configuration","instance","lastConfiguration","current","createMMKVHook","getter","key","mmkv","value","setValue","set","v","newValue","delete","Error","listener","addOnValueChangedListener","changedKey","remove","useMMKVString","getString","useMMKVNumber","getNumber","useMMKVBoolean","getBoolean","useMMKVObject","string","setString","undefined","JSON","parse","stringify"],"mappings":"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","sourcesContent":["import React, {\n useRef,\n useState,\n useMemo,\n useCallback,\n useEffect,\n} from 'react';\nimport { MMKV, MMKVConfiguration, MMKVInterface } from './MMKV';\n\nfunction isConfigurationEqual(\n left: MMKVConfiguration,\n right: MMKVConfiguration\n): boolean {\n return (\n left.encryptionKey === right.encryptionKey &&\n left.id === right.id &&\n left.path === right.path\n );\n}\n\nlet defaultInstance: MMKVInterface | null = null;\nfunction getDefaultInstance(): MMKVInterface {\n if (defaultInstance == null) {\n defaultInstance = new MMKV();\n }\n return defaultInstance;\n}\n\nexport function useMMKV(\n configuration: MMKVConfiguration\n): React.RefObject<MMKVInterface> {\n const instance = useRef<MMKVInterface>();\n\n const lastConfiguration = useRef<MMKVConfiguration>(configuration);\n if (!isConfigurationEqual(lastConfiguration.current, configuration)) {\n instance.current = new MMKV(configuration);\n }\n\n // @ts-expect-error it's not null, I promise.\n return instance;\n}\n\nfunction createMMKVHook<\n T extends boolean | number | (string | undefined),\n TSet extends T | undefined,\n TSetAction extends TSet | ((current: T) => TSet)\n>(getter: (instance: MMKVInterface, key: string) => T) {\n return (\n key: string,\n instance?: MMKVInterface\n ): [value: T, setValue: (value: TSetAction) => void] => {\n const mmkv = instance ?? getDefaultInstance();\n const [value, setValue] = useState(() => getter(mmkv, key));\n\n const set = useCallback(\n (v: TSetAction) => {\n const newValue = typeof v === 'function' ? v(value) : v;\n switch (typeof newValue) {\n case 'number':\n case 'string':\n case 'boolean':\n mmkv.set(key, newValue);\n break;\n case 'undefined':\n mmkv.delete(key);\n break;\n default:\n throw new Error(`MMKV: Type ${typeof newValue} is not supported!`);\n }\n },\n [key, mmkv, value]\n );\n\n useEffect(() => {\n const listener = mmkv.addOnValueChangedListener((changedKey) => {\n if (changedKey === key) {\n setValue(getter(mmkv, key));\n }\n });\n return () => listener.remove();\n }, [key, mmkv]);\n\n return useMemo(() => [value, set], [value, set]);\n };\n}\n\n/**\n * Use the string value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [username, setUsername] = useMMKVString(\"user.name\")\n * ```\n */\nexport const useMMKVString = createMMKVHook((instance, key) =>\n instance.getString(key)\n);\n\n/**\n * Use the number value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [age, setAge] = useMMKVNumber(\"user.age\")\n * ```\n */\nexport const useMMKVNumber = createMMKVHook((instance, key) =>\n instance.getNumber(key)\n);\n/**\n * Use the boolean value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * @example\n * ```ts\n * const [isPremiumAccount, setIsPremiumAccount] = useMMKVBoolean(\"user.isPremium\")\n * ```\n */\nexport const useMMKVBoolean = createMMKVHook((instance, key) =>\n instance.getBoolean(key)\n);\n/**\n * Use an object value of the given `key` from the given MMKV storage instance.\n *\n * If no instance is provided, a shared default instance will be used.\n *\n * The object will be serialized using `JSON`.\n *\n * @example\n * ```ts\n * const [user, setUser] = useMMKVObject<User>(\"user\")\n * ```\n */\nexport function useMMKVObject<T>(\n key: string,\n instance?: MMKVInterface\n): [value: T | undefined, setValue: (value: T) => void] {\n const [string, setString] = useMMKVString(key, instance);\n\n const value = useMemo(() => {\n if (string == null) return undefined;\n return JSON.parse(string) as T;\n }, [string]);\n const setValue = useCallback(\n (v: T) => {\n setString(JSON.stringify(v));\n },\n [setString]\n );\n\n return [value, setValue];\n}\n"]}
@@ -1,2 +1,3 @@
1
1
  export * from './MMKV';
2
+ export * from './hooks';
2
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAd","sourcesContent":["export * from './MMKV';\n"]}
1
+ {"version":3,"sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAd;AACA,cAAc,SAAd","sourcesContent":["export * from './MMKV';\nexport * from './hooks';\n"]}
@@ -1,3 +1,6 @@
1
+ interface Listener {
2
+ remove: () => void;
3
+ }
1
4
  /**
2
5
  * Used for configuration of a single MMKV instance.
3
6
  */
@@ -59,6 +62,10 @@ export interface MMKVInterface {
59
62
  * @default 0
60
63
  */
61
64
  getNumber: (key: string) => number;
65
+ /**
66
+ * Checks whether the given `key` is being stored in this MMKV instance.
67
+ */
68
+ contains: (key: string) => boolean;
62
69
  /**
63
70
  * Delete the given `key`.
64
71
  */
@@ -73,6 +80,10 @@ export interface MMKVInterface {
73
80
  * Delete all keys.
74
81
  */
75
82
  clearAll: () => void;
83
+ /**
84
+ * Adds a value changed listener.
85
+ */
86
+ addOnValueChangedListener: (onValueChanged: (key: string) => void) => Listener;
76
87
  }
77
88
  declare global {
78
89
  function mmkvCreateNewInstance(configuration: MMKVConfiguration): MMKVInterface;
@@ -83,17 +94,23 @@ declare global {
83
94
  export declare class MMKV implements MMKVInterface {
84
95
  private nativeInstance;
85
96
  private functionCache;
97
+ private id;
86
98
  /**
87
99
  * Creates a new MMKV instance with the given Configuration.
88
100
  * If no custom `id` is supplied, `'default'` will be used.
89
101
  */
90
102
  constructor(configuration?: MMKVConfiguration);
103
+ private get onValueChangedListeners();
91
104
  private getFunctionFromCache;
105
+ private onValuesAboutToChange;
92
106
  set(key: string, value: boolean | string | number): void;
93
107
  getBoolean(key: string): boolean;
94
108
  getString(key: string): string | undefined;
95
109
  getNumber(key: string): number;
110
+ contains(key: string): boolean;
96
111
  delete(key: string): void;
97
112
  getAllKeys(): string[];
98
113
  clearAll(): void;
114
+ addOnValueChangedListener(onValueChanged: (key: string) => void): Listener;
99
115
  }
116
+ export {};
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import { MMKVConfiguration, MMKVInterface } from './MMKV';
3
+ export declare function useMMKV(configuration: MMKVConfiguration): React.RefObject<MMKVInterface>;
4
+ /**
5
+ * Use the string value of the given `key` from the given MMKV storage instance.
6
+ *
7
+ * If no instance is provided, a shared default instance will be used.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const [username, setUsername] = useMMKVString("user.name")
12
+ * ```
13
+ */
14
+ export declare const useMMKVString: (key: string, instance?: MMKVInterface | undefined) => [value: string | undefined, setValue: (value: string | ((current: string | undefined) => string | undefined) | undefined) => void];
15
+ /**
16
+ * Use the number value of the given `key` from the given MMKV storage instance.
17
+ *
18
+ * If no instance is provided, a shared default instance will be used.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const [age, setAge] = useMMKVNumber("user.age")
23
+ * ```
24
+ */
25
+ export declare const useMMKVNumber: (key: string, instance?: MMKVInterface | undefined) => [value: number, setValue: (value: number | ((current: number) => number | undefined) | undefined) => void];
26
+ /**
27
+ * Use the boolean value of the given `key` from the given MMKV storage instance.
28
+ *
29
+ * If no instance is provided, a shared default instance will be used.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const [isPremiumAccount, setIsPremiumAccount] = useMMKVBoolean("user.isPremium")
34
+ * ```
35
+ */
36
+ export declare const useMMKVBoolean: (key: string, instance?: MMKVInterface | undefined) => [value: boolean, setValue: (value: boolean | ((current: boolean) => boolean | undefined) | undefined) => void];
37
+ /**
38
+ * Use an object value of the given `key` from the given MMKV storage instance.
39
+ *
40
+ * If no instance is provided, a shared default instance will be used.
41
+ *
42
+ * The object will be serialized using `JSON`.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const [user, setUser] = useMMKVObject<User>("user")
47
+ * ```
48
+ */
49
+ export declare function useMMKVObject<T>(key: string, instance?: MMKVInterface): [value: T | undefined, setValue: (value: T) => void];
@@ -1 +1,2 @@
1
1
  export * from './MMKV';
2
+ export * from './hooks';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-mmkv",
3
- "version": "1.3.3",
3
+ "version": "1.5.2",
4
4
  "description": "An efficient, small mobile key-value storage framework developed by WeChat. Works on Android and iOS.",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",