kutaisan-react-native-mmkv-storage
Version:
This library aims to provide a fast & reliable solution for you data storage needs in react-native apps. It uses [MMKV](https://github.com/Tencent/MMKV) by Tencent under the hood on Android and iOS both that is used by their WeChat app(more than 1 Billion
110 lines (93 loc) • 3.13 kB
JavaScript
import { useCallback, useEffect, useRef, useState } from "react";
import { methods } from "./constants";
import { getDataType, getInitialValue } from "./functions";
export const create = (storage) => (key, defaultValue) => {
if (!key || typeof key !== "string" || !storage)
throw new Error("Key and Storage are required parameters.");
return useMMKVStorage(key, storage, defaultValue);
};
export const useMMKVStorage = (key, storage, defaultValue) => {
const getValue = useCallback(
getInitialValue({ key, storage, kindValue: "value" }),
[key, storage]
);
const getValueType = useCallback(
getInitialValue({ key, storage, kindValue: "valueType" }),
[key, storage]
);
const [value, setValue] = useState(getValue);
const [valueType, setValueType] = useState(getValueType);
const prevKey = usePrevious(key);
const prevStorage = usePrevious(storage);
const prevValue = usePrevious(value);
useEffect(() => {
if (storage !== null) {
// This check prevents getInitialValue from being called twice when this hook intially loads
if (prevKey !== key || prevStorage !== storage) {
setValue(getValue);
setValueType(getValueType);
}
storage.ev.subscribe(`${key}:onwrite`, updateValue);
}
return () => {
if (storage != null) {
storage.ev.unsubscribe(`${key}:onwrite`, updateValue);
}
};
}, [prevKey, key, prevStorage, storage, getValue, getValueType]);
const updateValue = useCallback((event) => {
let type = getDataType(event.value);
let _value = event.value ? methods[type]["copy"](event.value) : null;
console.log(_value,type)
setValue(_value);
setValueType(type);
}, []);
const setNewValue = useCallback(
async (nextValue) => {
console.log(nextValue);
let updatedValue = nextValue;
if (typeof nextValue === "function") {
if (nextValue.constructor.name === "AsyncFunction") {
__DEV__ &&
console.warn(
`Attempting to use an async function as state setter is not allowed.`
);
return;
}
updatedValue = nextValue(prevValue);
}
let _value;
let _valueType = valueType;
if (updatedValue === null || updatedValue === undefined) {
storage.removeItem(key);
_valueType = null;
} else {
let _dataType = getDataType(updatedValue);
if (_valueType && _dataType !== valueType) {
__DEV__ &&
console.warn(
`Trying to set a ${_dataType} value to hook for type ${_valueType} is not allowed.`
);
return;
}
if (!valueType) {
_valueType = _dataType;
}
_value = updatedValue;
storage[methods[_valueType]["set"]](key, _value);
}
setValue(_value);
setValueType(_valueType);
return;
},
[valueType]
);
return [value || defaultValue, setNewValue];
};
function usePrevious(value) {
const ref = useRef(value);
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}