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 +11 -47
- package/android/build.gradle +1 -1
- package/android/src/main/cpp/MmkvHostObject.cpp +18 -0
- package/ios/MmkvHostObject.mm +20 -2
- package/lib/commonjs/MMKV.js +50 -9
- package/lib/commonjs/MMKV.js.map +1 -1
- package/lib/commonjs/hooks.js +139 -0
- package/lib/commonjs/hooks.js.map +1 -0
- package/lib/commonjs/index.js +13 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/MMKV.js +49 -9
- package/lib/module/MMKV.js.map +1 -1
- package/lib/module/hooks.js +124 -0
- package/lib/module/hooks.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/MMKV.d.ts +17 -0
- package/lib/typescript/hooks.d.ts +49 -0
- package/lib/typescript/index.d.ts +1 -0
- package/package.json +1 -1
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
|
-
##
|
|
159
|
+
## Documentation
|
|
155
160
|
|
|
156
|
-
|
|
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.
|
package/android/build.gradle
CHANGED
|
@@ -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,
|
package/ios/MmkvHostObject.mm
CHANGED
|
@@ -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();
|
package/lib/commonjs/MMKV.js
CHANGED
|
@@ -5,20 +5,15 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.MMKV = void 0;
|
|
7
7
|
|
|
8
|
-
|
|
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;
|
package/lib/commonjs/MMKV.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["MMKV.ts"],"names":["MMKV","constructor","configuration","id","global","mmkvCreateNewInstance","Error","nativeInstance","functionCache","getFunctionFromCache","functionName","
|
|
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":";;;;;;;;;;AAAA;;AAOA;;AAEA,SAASA,oBAAT,CACEC,IADF,EAEEC,KAFF,EAGW;AACT,SACED,IAAI,CAACE,aAAL,KAAuBD,KAAK,CAACC,aAA7B,IACAF,IAAI,CAACG,EAAL,KAAYF,KAAK,CAACE,EADlB,IAEAH,IAAI,CAACI,IAAL,KAAcH,KAAK,CAACG,IAHtB;AAKD;;AAED,IAAIC,eAAqC,GAAG,IAA5C;;AACA,SAASC,kBAAT,GAA6C;AAC3C,MAAID,eAAe,IAAI,IAAvB,EAA6B;AAC3BA,IAAAA,eAAe,GAAG,IAAIE,UAAJ,EAAlB;AACD;;AACD,SAAOF,eAAP;AACD;;AAEM,SAASG,OAAT,CACLC,aADK,EAE2B;AAChC,QAAMC,QAAQ,GAAG,oBAAjB;AAEA,QAAMC,iBAAiB,GAAG,mBAA0BF,aAA1B,CAA1B;;AACA,MAAI,CAACV,oBAAoB,CAACY,iBAAiB,CAACC,OAAnB,EAA4BH,aAA5B,CAAzB,EAAqE;AACnEC,IAAAA,QAAQ,CAACE,OAAT,GAAmB,IAAIL,UAAJ,CAASE,aAAT,CAAnB;AACD,GAN+B,CAQhC;;;AACA,SAAOC,QAAP;AACD;;AAED,SAASG,cAAT,CAIEC,MAJF,EAIuD;AACrD,SAAO,CACLC,GADK,EAELL,QAFK,KAGiD;AACtD,UAAMM,IAAI,GAAGN,QAAH,aAAGA,QAAH,cAAGA,QAAH,GAAeJ,kBAAkB,EAA3C;AACA,UAAM,CAACW,KAAD,EAAQC,QAAR,IAAoB,qBAAS,MAAMJ,MAAM,CAACE,IAAD,EAAOD,GAAP,CAArB,CAA1B;AAEA,UAAMI,GAAG,GAAG,wBACTC,CAAD,IAAmB;AACjB,YAAMC,QAAQ,GAAG,OAAOD,CAAP,KAAa,UAAb,GAA0BA,CAAC,CAACH,KAAD,CAA3B,GAAqCG,CAAtD;;AACA,cAAQ,OAAOC,QAAf;AACE,aAAK,QAAL;AACA,aAAK,QAAL;AACA,aAAK,SAAL;AACEL,UAAAA,IAAI,CAACG,GAAL,CAASJ,GAAT,EAAcM,QAAd;AACA;;AACF,aAAK,WAAL;AACEL,UAAAA,IAAI,CAACM,MAAL,CAAYP,GAAZ;AACA;;AACF;AACE,gBAAM,IAAIQ,KAAJ,CAAW,cAAa,OAAOF,QAAS,oBAAxC,CAAN;AAVJ;AAYD,KAfS,EAgBV,CAACN,GAAD,EAAMC,IAAN,EAAYC,KAAZ,CAhBU,CAAZ;AAmBA,0BAAU,MAAM;AACd,YAAMO,QAAQ,GAAGR,IAAI,CAACS,yBAAL,CAAgCC,UAAD,IAAgB;AAC9D,YAAIA,UAAU,KAAKX,GAAnB,EAAwB;AACtBG,UAAAA,QAAQ,CAACJ,MAAM,CAACE,IAAD,EAAOD,GAAP,CAAP,CAAR;AACD;AACF,OAJgB,CAAjB;AAKA,aAAO,MAAMS,QAAQ,CAACG,MAAT,EAAb;AACD,KAPD,EAOG,CAACZ,GAAD,EAAMC,IAAN,CAPH;AASA,WAAO,oBAAQ,MAAM,CAACC,KAAD,EAAQE,GAAR,CAAd,EAA4B,CAACF,KAAD,EAAQE,GAAR,CAA5B,CAAP;AACD,GApCD;AAqCD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,MAAMS,aAAa,GAAGf,cAAc,CAAC,CAACH,QAAD,EAAWK,GAAX,KAC1CL,QAAQ,CAACmB,SAAT,CAAmBd,GAAnB,CADyC,CAApC;AAIP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,MAAMe,aAAa,GAAGjB,cAAc,CAAC,CAACH,QAAD,EAAWK,GAAX,KAC1CL,QAAQ,CAACqB,SAAT,CAAmBhB,GAAnB,CADyC,CAApC;AAGP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,MAAMiB,cAAc,GAAGnB,cAAc,CAAC,CAACH,QAAD,EAAWK,GAAX,KAC3CL,QAAQ,CAACuB,UAAT,CAAoBlB,GAApB,CAD0C,CAArC;AAGP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;AACO,SAASmB,aAAT,CACLnB,GADK,EAELL,QAFK,EAGiD;AACtD,QAAM,CAACyB,MAAD,EAASC,SAAT,IAAsBR,aAAa,CAACb,GAAD,EAAML,QAAN,CAAzC;AAEA,QAAMO,KAAK,GAAG,oBAAQ,MAAM;AAC1B,QAAIkB,MAAM,IAAI,IAAd,EAAoB,OAAOE,SAAP;AACpB,WAAOC,IAAI,CAACC,KAAL,CAAWJ,MAAX,CAAP;AACD,GAHa,EAGX,CAACA,MAAD,CAHW,CAAd;AAIA,QAAMjB,QAAQ,GAAG,wBACdE,CAAD,IAAU;AACRgB,IAAAA,SAAS,CAACE,IAAI,CAACE,SAAL,CAAepB,CAAf,CAAD,CAAT;AACD,GAHc,EAIf,CAACgB,SAAD,CAJe,CAAjB;AAOA,SAAO,CAACnB,KAAD,EAAQC,QAAR,CAAP;AACD","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"]}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -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"]}
|
package/lib/module/MMKV.js
CHANGED
|
@@ -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
|
-
|
|
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
|
package/lib/module/MMKV.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["MMKV.ts"],"names":["MMKV","constructor","configuration","id","global","mmkvCreateNewInstance","Error","nativeInstance","functionCache","getFunctionFromCache","functionName","
|
|
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":";;AAAA,SAASA,uBAAT,QAAwC,cAAxC;AAqGA,MAAMC,uBAAuB,GAAG,IAAIC,GAAJ,EAAhC;AAEA;AACA;AACA;;AACA,OAAO,MAAMC,IAAN,CAAoC;AAKzC;AACF;AACA;AACA;AACEC,EAAAA,WAAW,CAACC,aAAgC,GAAG;AAAEC,IAAAA,EAAE,EAAE;AAAN,GAApC,EAA4D;AAAA;;AAAA;;AAAA;;AACrE,QAAIC,MAAM,CAACC,qBAAP,IAAgC,IAApC,EAA0C;AACxC,YAAM,IAAIC,KAAJ,CACJ,0MADI,CAAN;AAGD;;AACD,SAAKH,EAAL,GAAUD,aAAa,CAACC,EAAxB;AACA,SAAKI,cAAL,GAAsBH,MAAM,CAACC,qBAAP,CAA6BH,aAA7B,CAAtB;AACA,SAAKM,aAAL,GAAqB,EAArB;AACD;;AAEkC,MAAvBV,uBAAuB,GAAG;AACpC,QAAI,CAACA,uBAAuB,CAACW,GAAxB,CAA4B,KAAKN,EAAjC,CAAL,EAA2C;AACzCL,MAAAA,uBAAuB,CAACY,GAAxB,CAA4B,KAAKP,EAAjC,EAAqC,EAArC;AACD;;AACD,WAAOL,uBAAuB,CAACa,GAAxB,CAA4B,KAAKR,EAAjC,CAAP;AACD;;AAEOS,EAAAA,oBAAoB,CAC1BC,YAD0B,EAER;AAClB,QAAI,KAAKL,aAAL,CAAmBK,YAAnB,KAAoC,IAAxC,EAA8C;AAC5C,WAAKL,aAAL,CAAmBK,YAAnB,IAAmC,KAAKN,cAAL,CAAoBM,YAApB,CAAnC;AACD;;AACD,WAAO,KAAKL,aAAL,CAAmBK,YAAnB,CAAP;AACD;;AAEOC,EAAAA,qBAAqB,CAACC,IAAD,EAAiB;AAC5C,QAAI,KAAKjB,uBAAL,CAA6BkB,MAA7B,KAAwC,CAA5C,EAA+C;AAE/CC,IAAAA,YAAY,CAAC,MAAM;AACjBpB,MAAAA,uBAAuB,CAAC,MAAM;AAC5B,aAAK,MAAMqB,GAAX,IAAkBH,IAAlB,EAAwB;AACtB,eAAK,MAAMI,QAAX,IAAuB,KAAKrB,uBAA5B,EAAqD;AACnDqB,YAAAA,QAAQ,CAACD,GAAD,CAAR;AACD;AACF;AACF,OANsB,CAAvB;AAOD,KARW,CAAZ;AASD;;AAEDR,EAAAA,GAAG,CAACQ,GAAD,EAAcE,KAAd,EAAsD;AACvD,SAAKN,qBAAL,CAA2B,CAACI,GAAD,CAA3B;AAEA,UAAMG,IAAI,GAAG,KAAKT,oBAAL,CAA0B,KAA1B,CAAb;AACA,WAAOS,IAAI,CAACH,GAAD,EAAME,KAAN,CAAX;AACD;;AACDE,EAAAA,UAAU,CAACJ,GAAD,EAAuB;AAC/B,UAAMG,IAAI,GAAG,KAAKT,oBAAL,CAA0B,YAA1B,CAAb;AACA,WAAOS,IAAI,CAACH,GAAD,CAAX;AACD;;AACDK,EAAAA,SAAS,CAACL,GAAD,EAAkC;AACzC,UAAMG,IAAI,GAAG,KAAKT,oBAAL,CAA0B,WAA1B,CAAb;AACA,WAAOS,IAAI,CAACH,GAAD,CAAX;AACD;;AACDM,EAAAA,SAAS,CAACN,GAAD,EAAsB;AAC7B,UAAMG,IAAI,GAAG,KAAKT,oBAAL,CAA0B,WAA1B,CAAb;AACA,WAAOS,IAAI,CAACH,GAAD,CAAX;AACD;;AACDO,EAAAA,QAAQ,CAACP,GAAD,EAAuB;AAC7B,UAAMG,IAAI,GAAG,KAAKT,oBAAL,CAA0B,UAA1B,CAAb;AACA,WAAOS,IAAI,CAACH,GAAD,CAAX;AACD;;AACDQ,EAAAA,MAAM,CAACR,GAAD,EAAoB;AACxB,SAAKJ,qBAAL,CAA2B,CAACI,GAAD,CAA3B;AAEA,UAAMG,IAAI,GAAG,KAAKT,oBAAL,CAA0B,QAA1B,CAAb;AACA,WAAOS,IAAI,CAACH,GAAD,CAAX;AACD;;AACDS,EAAAA,UAAU,GAAa;AACrB,UAAMN,IAAI,GAAG,KAAKT,oBAAL,CAA0B,YAA1B,CAAb;AACA,WAAOS,IAAI,EAAX;AACD;;AACDO,EAAAA,QAAQ,GAAS;AACf,UAAMb,IAAI,GAAG,KAAKY,UAAL,EAAb;AACA,SAAKb,qBAAL,CAA2BC,IAA3B;AAEA,UAAMM,IAAI,GAAG,KAAKT,oBAAL,CAA0B,UAA1B,CAAb;AACA,WAAOS,IAAI,EAAX;AACD;;AAEDQ,EAAAA,yBAAyB,CAACC,cAAD,EAAkD;AACzE,SAAKhC,uBAAL,CAA6BiC,IAA7B,CAAkCD,cAAlC;AAEA,WAAO;AACLE,MAAAA,MAAM,EAAE,MAAM;AACZ,cAAMC,KAAK,GAAG,KAAKnC,uBAAL,CAA6BoC,OAA7B,CAAqCJ,cAArC,CAAd;;AACA,YAAIG,KAAK,KAAK,CAAC,CAAf,EAAkB;AAChB,eAAKnC,uBAAL,CAA6BqC,MAA7B,CAAoCF,KAApC,EAA2C,CAA3C;AACD;AACF;AANI,KAAP;AAQD;;AArGwC","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"]}
|
package/lib/module/index.js
CHANGED
package/lib/module/index.js.map
CHANGED
|
@@ -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"]}
|
package/lib/typescript/MMKV.d.ts
CHANGED
|
@@ -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];
|
package/package.json
CHANGED