react-native-mmkv 2.1.0 → 2.2.0
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 +2 -1
- package/android/CMakeLists.txt +3 -2
- package/ios/MmkvModule.mm +16 -14
- package/lib/commonjs/hooks.js +19 -3
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/module/hooks.js +19 -3
- package/lib/module/hooks.js.map +1 -1
- package/lib/typescript/hooks.d.ts +9 -2
- package/package.json +26 -2
package/README.md
CHANGED
|
@@ -104,7 +104,7 @@ This creates a new storage instance using a custom MMKV storage ID. By using a c
|
|
|
104
104
|
|
|
105
105
|
The following values can be configured:
|
|
106
106
|
|
|
107
|
-
* `id`: The MMKV instance's ID. If you want to use multiple instances, use different IDs. For example, you can separte the global app's storage and a logged-in user's storage. (
|
|
107
|
+
* `id`: The MMKV instance's ID. If you want to use multiple instances, use different IDs. For example, you can separte the global app's storage and a logged-in user's storage. (required if `path` or `encryptionKey` fields are specified, otherwise defaults to: `'mmkv.default'`)
|
|
108
108
|
* `path`: The MMKV instance's root path. By default, MMKV stores file inside `$(Documents)/mmkv/`. You can customize MMKV's root directory on MMKV initialization (documentation: [iOS](https://github.com/Tencent/MMKV/wiki/iOS_advance#customize-location) / [Android](https://github.com/Tencent/MMKV/wiki/android_advance#customize-location))
|
|
109
109
|
* `encryptionKey`: The MMKV instance's encryption/decryption key. By default, MMKV stores all key-values in plain text on file, relying on iOS's/Android's sandbox to make sure the file is encrypted. Should you worry about information leaking, you can choose to encrypt MMKV. (documentation: [iOS](https://github.com/Tencent/MMKV/wiki/iOS_advance#encryption) / [Android](https://github.com/Tencent/MMKV/wiki/android_advance#encryption))
|
|
110
110
|
|
|
@@ -174,6 +174,7 @@ storage.recrypt(undefined)
|
|
|
174
174
|
* [Using MMKV with redux-persist](./docs/WRAPPER_REDUX.md)
|
|
175
175
|
* [Using MMKV with mobx-persist-storage](./docs/WRAPPER_MOBX.md)
|
|
176
176
|
* [Using MMKV with mobx-persist](./docs/WRAPPER_MOBXPERSIST.md)
|
|
177
|
+
* [Using MMKV with zustand persist-middleware](./docs/WRAPPER_ZUSTAND_PERSIST_MIDDLEWARE.md)
|
|
177
178
|
* [How is this library different from **react-native-mmkv-storage**?](https://github.com/mrousavy/react-native-mmkv/issues/100#issuecomment-886477361)
|
|
178
179
|
|
|
179
180
|
## Limitations
|
package/android/CMakeLists.txt
CHANGED
package/ios/MmkvModule.mm
CHANGED
|
@@ -28,39 +28,41 @@ RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install:(nullable NSString*)storageDirect
|
|
|
28
28
|
if (cxxBridge == nil) {
|
|
29
29
|
return @false;
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
using namespace facebook;
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
auto jsiRuntime = (jsi::Runtime*) cxxBridge.runtime;
|
|
35
35
|
if (jsiRuntime == nil) {
|
|
36
36
|
return @false;
|
|
37
37
|
}
|
|
38
38
|
auto& runtime = *jsiRuntime;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
|
|
40
|
+
RCTUnsafeExecuteOnMainQueueSync(^{
|
|
41
|
+
[MMKV initializeMMKV:storageDirectory];
|
|
42
|
+
});
|
|
43
|
+
|
|
42
44
|
// MMKV.createNewInstance()
|
|
43
45
|
auto mmkvCreateNewInstance = jsi::Function::createFromHostFunction(runtime,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
jsi::PropNameID::forAscii(runtime, "mmkvCreateNewInstance"),
|
|
47
|
+
1,
|
|
48
|
+
[](jsi::Runtime& runtime,
|
|
49
|
+
const jsi::Value& thisValue,
|
|
50
|
+
const jsi::Value* arguments,
|
|
51
|
+
size_t count) -> jsi::Value {
|
|
50
52
|
if (count != 1) {
|
|
51
53
|
throw jsi::JSError(runtime, "MMKV.createNewInstance(..) expects one argument (object)!");
|
|
52
54
|
}
|
|
53
55
|
jsi::Object config = arguments[0].asObject(runtime);
|
|
54
|
-
|
|
56
|
+
|
|
55
57
|
NSString* instanceId = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"id" runtime:runtime];
|
|
56
58
|
NSString* path = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"path" runtime:runtime];
|
|
57
59
|
NSString* encryptionKey = [MmkvModule getPropertyAsStringOrNilFromObject:config propertyName:"encryptionKey" runtime:runtime];
|
|
58
|
-
|
|
60
|
+
|
|
59
61
|
auto instance = std::make_shared<MmkvHostObject>(instanceId, path, encryptionKey);
|
|
60
62
|
return jsi::Object::createFromHostObject(runtime, instance);
|
|
61
63
|
});
|
|
62
64
|
runtime.global().setProperty(runtime, "mmkvCreateNewInstance", std::move(mmkvCreateNewInstance));
|
|
63
|
-
|
|
65
|
+
|
|
64
66
|
NSLog(@"Installed global.mmkvCreateNewInstance!");
|
|
65
67
|
return @true;
|
|
66
68
|
}
|
package/lib/commonjs/hooks.js
CHANGED
|
@@ -15,6 +15,7 @@ var _react = require("react");
|
|
|
15
15
|
var _MMKV = require("./MMKV");
|
|
16
16
|
|
|
17
17
|
function isConfigurationEqual(left, right) {
|
|
18
|
+
if (left == null || right == null) return left == null && right == null;
|
|
18
19
|
return left.encryptionKey === right.encryptionKey && left.id === right.id && left.path === right.path;
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -27,12 +28,17 @@ function getDefaultInstance() {
|
|
|
27
28
|
|
|
28
29
|
return defaultInstance;
|
|
29
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Use the default, shared MMKV instance.
|
|
33
|
+
*/
|
|
34
|
+
|
|
30
35
|
|
|
31
36
|
function useMMKV(configuration) {
|
|
32
37
|
const instance = (0, _react.useRef)();
|
|
33
38
|
const lastConfiguration = (0, _react.useRef)();
|
|
39
|
+
if (configuration == null) return getDefaultInstance();
|
|
34
40
|
|
|
35
|
-
if (
|
|
41
|
+
if (instance.current == null || !isConfigurationEqual(lastConfiguration.current, configuration)) {
|
|
36
42
|
lastConfiguration.current = configuration;
|
|
37
43
|
instance.current = new _MMKV.MMKV(configuration);
|
|
38
44
|
} // @ts-expect-error it's not null, I promise.
|
|
@@ -46,7 +52,8 @@ function createMMKVHook(getter) {
|
|
|
46
52
|
const mmkv = instance !== null && instance !== void 0 ? instance : getDefaultInstance();
|
|
47
53
|
const [value, setValue] = (0, _react.useState)(() => getter(mmkv, key));
|
|
48
54
|
const valueRef = (0, _react.useRef)(value);
|
|
49
|
-
valueRef.current = value;
|
|
55
|
+
valueRef.current = value; // update value by user set
|
|
56
|
+
|
|
50
57
|
const set = (0, _react.useCallback)(v => {
|
|
51
58
|
const newValue = typeof v === 'function' ? v(valueRef.current) : v;
|
|
52
59
|
|
|
@@ -64,7 +71,16 @@ function createMMKVHook(getter) {
|
|
|
64
71
|
default:
|
|
65
72
|
throw new Error(`MMKV: Type ${typeof newValue} is not supported!`);
|
|
66
73
|
}
|
|
67
|
-
}, [key, mmkv]);
|
|
74
|
+
}, [key, mmkv]); // update value if key changes
|
|
75
|
+
|
|
76
|
+
const keyRef = (0, _react.useRef)(key);
|
|
77
|
+
(0, _react.useEffect)(() => {
|
|
78
|
+
if (key !== keyRef.current) {
|
|
79
|
+
setValue(getter(mmkv, key));
|
|
80
|
+
keyRef.current = key;
|
|
81
|
+
}
|
|
82
|
+
}, [key, mmkv]); // update value if it changes somewhere else (second hook, same key)
|
|
83
|
+
|
|
68
84
|
(0, _react.useEffect)(() => {
|
|
69
85
|
const listener = mmkv.addOnValueChangedListener(changedKey => {
|
|
70
86
|
if (changedKey === key) {
|
|
@@ -1 +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","valueRef","set","v","newValue","delete","Error","listener","addOnValueChangedListener","changedKey","remove","useMMKVString","getString","useMMKVNumber","getNumber","useMMKVBoolean","getBoolean","useMMKVObject","string","setString","undefined","JSON","parse","stringify","useMMKVListener","valueChangedListener","ref"],"mappings":"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","sourcesContent":["import React, {\n useRef,\n useState,\n useMemo,\n useCallback,\n useEffect,\n} from 'react';\nimport { MMKV, MMKVConfiguration } 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: MMKV | null = null;\nfunction getDefaultInstance(): MMKV {\n if (defaultInstance == null) {\n defaultInstance = new MMKV();\n }\n return defaultInstance;\n}\n\nexport function useMMKV(\n configuration: MMKVConfiguration\n): React.RefObject<MMKV> {\n const instance = useRef<MMKV>();\n\n const lastConfiguration = useRef<MMKVConfiguration>();\n if (\n lastConfiguration.current == null ||\n !isConfigurationEqual(lastConfiguration.current, configuration)\n ) {\n 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: MMKV, key: string) => T) {\n return (\n key: string,\n instance?: MMKV\n ): [value: T, setValue: (value: TSetAction) => void] => {\n const mmkv = instance ?? getDefaultInstance();\n const [value, setValue] = useState(() => getter(mmkv, key));\n const valueRef = useRef<T>(value);\n valueRef.current = value;\n\n const set = useCallback(\n (v: TSetAction) => {\n const newValue = typeof v === 'function' ? v(valueRef.current) : 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]\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 [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?: MMKV\n): [value: T | undefined, setValue: (value: T | undefined) => 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 | undefined) => {\n if (v == null) {\n // Clear the Value\n setString(undefined);\n } else {\n // Store the Object as a serialized Value\n setString(JSON.stringify(v));\n }\n },\n [setString]\n );\n\n return [value, setValue];\n}\n\n/**\n * Listen for changes in the given MMKV storage instance.\n * If no instance is passed, the default instance will be used.\n * @param valueChangedListener The function to call whenever a value inside the storage instance changes\n * @param instance The instance to listen to changes to (or the default instance)\n *\n * @example\n * ```ts\n * useMMKVListener((key) => {\n * console.log(`Value for \"${key}\" changed!`)\n * })\n * ```\n */\nexport function useMMKVListener(\n valueChangedListener: (key: string) => void,\n instance?: MMKV\n): void {\n const ref = useRef(valueChangedListener);\n ref.current = valueChangedListener;\n\n const mmkv = instance ?? getDefaultInstance();\n\n useEffect(() => {\n const listener = mmkv.addOnValueChangedListener((changedKey) => {\n ref.current(changedKey);\n });\n return () => listener.remove();\n }, [mmkv]);\n}\n"]}
|
|
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","valueRef","set","v","newValue","delete","Error","keyRef","listener","addOnValueChangedListener","changedKey","remove","useMMKVString","getString","useMMKVNumber","getNumber","useMMKVBoolean","getBoolean","useMMKVObject","string","setString","undefined","JSON","parse","stringify","useMMKVListener","valueChangedListener","ref"],"mappings":"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","sourcesContent":["import { useRef, useState, useMemo, useCallback, useEffect } from 'react';\nimport { MMKV, MMKVConfiguration } from './MMKV';\n\nfunction isConfigurationEqual(\n left?: MMKVConfiguration,\n right?: MMKVConfiguration\n): boolean {\n if (left == null || right == null) return left == null && right == null;\n\n return (\n left.encryptionKey === right.encryptionKey &&\n left.id === right.id &&\n left.path === right.path\n );\n}\n\nlet defaultInstance: MMKV | null = null;\nfunction getDefaultInstance(): MMKV {\n if (defaultInstance == null) {\n defaultInstance = new MMKV();\n }\n return defaultInstance;\n}\n\n/**\n * Use the default, shared MMKV instance.\n */\nexport function useMMKV(): MMKV;\n/**\n * Use a custom MMKV instance with the given configuration.\n * @param configuration The configuration to initialize the MMKV instance with. Does not have to be memoized.\n */\nexport function useMMKV(configuration: MMKVConfiguration): MMKV;\nexport function useMMKV(configuration?: MMKVConfiguration): MMKV {\n const instance = useRef<MMKV>();\n const lastConfiguration = useRef<MMKVConfiguration>();\n\n if (configuration == null) return getDefaultInstance();\n\n if (\n instance.current == null ||\n !isConfigurationEqual(lastConfiguration.current, configuration)\n ) {\n 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: MMKV, key: string) => T) {\n return (\n key: string,\n instance?: MMKV\n ): [value: T, setValue: (value: TSetAction) => void] => {\n const mmkv = instance ?? getDefaultInstance();\n const [value, setValue] = useState(() => getter(mmkv, key));\n const valueRef = useRef<T>(value);\n valueRef.current = value;\n\n // update value by user set\n const set = useCallback(\n (v: TSetAction) => {\n const newValue = typeof v === 'function' ? v(valueRef.current) : 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]\n );\n\n // update value if key changes\n const keyRef = useRef(key);\n useEffect(() => {\n if (key !== keyRef.current) {\n setValue(getter(mmkv, key));\n keyRef.current = key;\n }\n }, [key, mmkv]);\n\n // update value if it changes somewhere else (second hook, same key)\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 [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?: MMKV\n): [value: T | undefined, setValue: (value: T | undefined) => 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 | undefined) => {\n if (v == null) {\n // Clear the Value\n setString(undefined);\n } else {\n // Store the Object as a serialized Value\n setString(JSON.stringify(v));\n }\n },\n [setString]\n );\n\n return [value, setValue];\n}\n\n/**\n * Listen for changes in the given MMKV storage instance.\n * If no instance is passed, the default instance will be used.\n * @param valueChangedListener The function to call whenever a value inside the storage instance changes\n * @param instance The instance to listen to changes to (or the default instance)\n *\n * @example\n * ```ts\n * useMMKVListener((key) => {\n * console.log(`Value for \"${key}\" changed!`)\n * })\n * ```\n */\nexport function useMMKVListener(\n valueChangedListener: (key: string) => void,\n instance?: MMKV\n): void {\n const ref = useRef(valueChangedListener);\n ref.current = valueChangedListener;\n\n const mmkv = instance ?? getDefaultInstance();\n\n useEffect(() => {\n const listener = mmkv.addOnValueChangedListener((changedKey) => {\n ref.current(changedKey);\n });\n return () => listener.remove();\n }, [mmkv]);\n}\n"]}
|
package/lib/module/hooks.js
CHANGED
|
@@ -2,6 +2,7 @@ import { useRef, useState, useMemo, useCallback, useEffect } from 'react';
|
|
|
2
2
|
import { MMKV } from './MMKV';
|
|
3
3
|
|
|
4
4
|
function isConfigurationEqual(left, right) {
|
|
5
|
+
if (left == null || right == null) return left == null && right == null;
|
|
5
6
|
return left.encryptionKey === right.encryptionKey && left.id === right.id && left.path === right.path;
|
|
6
7
|
}
|
|
7
8
|
|
|
@@ -14,12 +15,17 @@ function getDefaultInstance() {
|
|
|
14
15
|
|
|
15
16
|
return defaultInstance;
|
|
16
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Use the default, shared MMKV instance.
|
|
20
|
+
*/
|
|
21
|
+
|
|
17
22
|
|
|
18
23
|
export function useMMKV(configuration) {
|
|
19
24
|
const instance = useRef();
|
|
20
25
|
const lastConfiguration = useRef();
|
|
26
|
+
if (configuration == null) return getDefaultInstance();
|
|
21
27
|
|
|
22
|
-
if (
|
|
28
|
+
if (instance.current == null || !isConfigurationEqual(lastConfiguration.current, configuration)) {
|
|
23
29
|
lastConfiguration.current = configuration;
|
|
24
30
|
instance.current = new MMKV(configuration);
|
|
25
31
|
} // @ts-expect-error it's not null, I promise.
|
|
@@ -33,7 +39,8 @@ function createMMKVHook(getter) {
|
|
|
33
39
|
const mmkv = instance !== null && instance !== void 0 ? instance : getDefaultInstance();
|
|
34
40
|
const [value, setValue] = useState(() => getter(mmkv, key));
|
|
35
41
|
const valueRef = useRef(value);
|
|
36
|
-
valueRef.current = value;
|
|
42
|
+
valueRef.current = value; // update value by user set
|
|
43
|
+
|
|
37
44
|
const set = useCallback(v => {
|
|
38
45
|
const newValue = typeof v === 'function' ? v(valueRef.current) : v;
|
|
39
46
|
|
|
@@ -51,7 +58,16 @@ function createMMKVHook(getter) {
|
|
|
51
58
|
default:
|
|
52
59
|
throw new Error(`MMKV: Type ${typeof newValue} is not supported!`);
|
|
53
60
|
}
|
|
54
|
-
}, [key, mmkv]);
|
|
61
|
+
}, [key, mmkv]); // update value if key changes
|
|
62
|
+
|
|
63
|
+
const keyRef = useRef(key);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (key !== keyRef.current) {
|
|
66
|
+
setValue(getter(mmkv, key));
|
|
67
|
+
keyRef.current = key;
|
|
68
|
+
}
|
|
69
|
+
}, [key, mmkv]); // update value if it changes somewhere else (second hook, same key)
|
|
70
|
+
|
|
55
71
|
useEffect(() => {
|
|
56
72
|
const listener = mmkv.addOnValueChangedListener(changedKey => {
|
|
57
73
|
if (changedKey === key) {
|
package/lib/module/hooks.js.map
CHANGED
|
@@ -1 +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","valueRef","set","v","newValue","delete","Error","listener","addOnValueChangedListener","changedKey","remove","useMMKVString","getString","useMMKVNumber","getNumber","useMMKVBoolean","getBoolean","useMMKVObject","string","setString","undefined","JSON","parse","stringify","useMMKVListener","valueChangedListener","ref"],"mappings":"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","sourcesContent":["import React, {\n useRef,\n useState,\n useMemo,\n useCallback,\n useEffect,\n} from 'react';\nimport { MMKV, MMKVConfiguration } 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: MMKV | null = null;\nfunction getDefaultInstance(): MMKV {\n if (defaultInstance == null) {\n defaultInstance = new MMKV();\n }\n return defaultInstance;\n}\n\nexport function useMMKV(\n configuration: MMKVConfiguration\n): React.RefObject<MMKV> {\n const instance = useRef<MMKV>();\n\n const lastConfiguration = useRef<MMKVConfiguration>();\n if (\n lastConfiguration.current == null ||\n !isConfigurationEqual(lastConfiguration.current, configuration)\n ) {\n 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: MMKV, key: string) => T) {\n return (\n key: string,\n instance?: MMKV\n ): [value: T, setValue: (value: TSetAction) => void] => {\n const mmkv = instance ?? getDefaultInstance();\n const [value, setValue] = useState(() => getter(mmkv, key));\n const valueRef = useRef<T>(value);\n valueRef.current = value;\n\n const set = useCallback(\n (v: TSetAction) => {\n const newValue = typeof v === 'function' ? v(valueRef.current) : 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]\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 [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?: MMKV\n): [value: T | undefined, setValue: (value: T | undefined) => 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 | undefined) => {\n if (v == null) {\n // Clear the Value\n setString(undefined);\n } else {\n // Store the Object as a serialized Value\n setString(JSON.stringify(v));\n }\n },\n [setString]\n );\n\n return [value, setValue];\n}\n\n/**\n * Listen for changes in the given MMKV storage instance.\n * If no instance is passed, the default instance will be used.\n * @param valueChangedListener The function to call whenever a value inside the storage instance changes\n * @param instance The instance to listen to changes to (or the default instance)\n *\n * @example\n * ```ts\n * useMMKVListener((key) => {\n * console.log(`Value for \"${key}\" changed!`)\n * })\n * ```\n */\nexport function useMMKVListener(\n valueChangedListener: (key: string) => void,\n instance?: MMKV\n): void {\n const ref = useRef(valueChangedListener);\n ref.current = valueChangedListener;\n\n const mmkv = instance ?? getDefaultInstance();\n\n useEffect(() => {\n const listener = mmkv.addOnValueChangedListener((changedKey) => {\n ref.current(changedKey);\n });\n return () => listener.remove();\n }, [mmkv]);\n}\n"]}
|
|
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","valueRef","set","v","newValue","delete","Error","keyRef","listener","addOnValueChangedListener","changedKey","remove","useMMKVString","getString","useMMKVNumber","getNumber","useMMKVBoolean","getBoolean","useMMKVObject","string","setString","undefined","JSON","parse","stringify","useMMKVListener","valueChangedListener","ref"],"mappings":"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","sourcesContent":["import { useRef, useState, useMemo, useCallback, useEffect } from 'react';\nimport { MMKV, MMKVConfiguration } from './MMKV';\n\nfunction isConfigurationEqual(\n left?: MMKVConfiguration,\n right?: MMKVConfiguration\n): boolean {\n if (left == null || right == null) return left == null && right == null;\n\n return (\n left.encryptionKey === right.encryptionKey &&\n left.id === right.id &&\n left.path === right.path\n );\n}\n\nlet defaultInstance: MMKV | null = null;\nfunction getDefaultInstance(): MMKV {\n if (defaultInstance == null) {\n defaultInstance = new MMKV();\n }\n return defaultInstance;\n}\n\n/**\n * Use the default, shared MMKV instance.\n */\nexport function useMMKV(): MMKV;\n/**\n * Use a custom MMKV instance with the given configuration.\n * @param configuration The configuration to initialize the MMKV instance with. Does not have to be memoized.\n */\nexport function useMMKV(configuration: MMKVConfiguration): MMKV;\nexport function useMMKV(configuration?: MMKVConfiguration): MMKV {\n const instance = useRef<MMKV>();\n const lastConfiguration = useRef<MMKVConfiguration>();\n\n if (configuration == null) return getDefaultInstance();\n\n if (\n instance.current == null ||\n !isConfigurationEqual(lastConfiguration.current, configuration)\n ) {\n 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: MMKV, key: string) => T) {\n return (\n key: string,\n instance?: MMKV\n ): [value: T, setValue: (value: TSetAction) => void] => {\n const mmkv = instance ?? getDefaultInstance();\n const [value, setValue] = useState(() => getter(mmkv, key));\n const valueRef = useRef<T>(value);\n valueRef.current = value;\n\n // update value by user set\n const set = useCallback(\n (v: TSetAction) => {\n const newValue = typeof v === 'function' ? v(valueRef.current) : 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]\n );\n\n // update value if key changes\n const keyRef = useRef(key);\n useEffect(() => {\n if (key !== keyRef.current) {\n setValue(getter(mmkv, key));\n keyRef.current = key;\n }\n }, [key, mmkv]);\n\n // update value if it changes somewhere else (second hook, same key)\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 [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?: MMKV\n): [value: T | undefined, setValue: (value: T | undefined) => 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 | undefined) => {\n if (v == null) {\n // Clear the Value\n setString(undefined);\n } else {\n // Store the Object as a serialized Value\n setString(JSON.stringify(v));\n }\n },\n [setString]\n );\n\n return [value, setValue];\n}\n\n/**\n * Listen for changes in the given MMKV storage instance.\n * If no instance is passed, the default instance will be used.\n * @param valueChangedListener The function to call whenever a value inside the storage instance changes\n * @param instance The instance to listen to changes to (or the default instance)\n *\n * @example\n * ```ts\n * useMMKVListener((key) => {\n * console.log(`Value for \"${key}\" changed!`)\n * })\n * ```\n */\nexport function useMMKVListener(\n valueChangedListener: (key: string) => void,\n instance?: MMKV\n): void {\n const ref = useRef(valueChangedListener);\n ref.current = valueChangedListener;\n\n const mmkv = instance ?? getDefaultInstance();\n\n useEffect(() => {\n const listener = mmkv.addOnValueChangedListener((changedKey) => {\n ref.current(changedKey);\n });\n return () => listener.remove();\n }, [mmkv]);\n}\n"]}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import { MMKV, MMKVConfiguration } from './MMKV';
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Use the default, shared MMKV instance.
|
|
4
|
+
*/
|
|
5
|
+
export declare function useMMKV(): MMKV;
|
|
6
|
+
/**
|
|
7
|
+
* Use a custom MMKV instance with the given configuration.
|
|
8
|
+
* @param configuration The configuration to initialize the MMKV instance with. Does not have to be memoized.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useMMKV(configuration: MMKVConfiguration): MMKV;
|
|
4
11
|
/**
|
|
5
12
|
* Use the string value of the given `key` from the given MMKV storage instance.
|
|
6
13
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-mmkv",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "The fastest key/value storage for React Native. ~30x faster than AsyncStorage! Works on Android, iOS and Web.",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -91,7 +91,31 @@
|
|
|
91
91
|
},
|
|
92
92
|
"plugins": {
|
|
93
93
|
"@release-it/conventional-changelog": {
|
|
94
|
-
"preset":
|
|
94
|
+
"preset": {
|
|
95
|
+
"name": "conventionalcommits",
|
|
96
|
+
"types": [
|
|
97
|
+
{
|
|
98
|
+
"type": "feat",
|
|
99
|
+
"section": "✨ Features"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"type": "fix",
|
|
103
|
+
"section": "🐛 Bug Fixes"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"type": "perf",
|
|
107
|
+
"section": "💨 Performance Improvements"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"type": "chore(deps)",
|
|
111
|
+
"section": "🛠️ Dependency Upgrades"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"type": "docs",
|
|
115
|
+
"section": "📚 Documentation"
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
}
|
|
95
119
|
}
|
|
96
120
|
}
|
|
97
121
|
},
|